blob: 0d0f0053bb1151db200c2fdf403009fea84f4ee3 [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>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090035#include <net/protocol.h>
36#include <linux/skbuff.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090037#include <net/raw.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090038#include <linux/notifier.h>
39#include <linux/if_arp.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090040#include <net/checksum.h>
41#include <net/netlink.h>
Patrick McHardyd1db2752010-05-11 14:40:55 +020042#include <net/fib_rules.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090043
44#include <net/ipv6.h>
45#include <net/ip6_route.h>
46#include <linux/mroute6.h>
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +090047#include <linux/pim.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090048#include <net/addrconf.h>
49#include <linux/netfilter_ipv6.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040050#include <linux/export.h>
Dave Jones5d6e4302009-01-31 00:51:49 -080051#include <net/ip6_checksum.h>
Nicolas Dichteld67b8c62012-12-04 01:13:35 +000052#include <linux/netconf.h>
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090053
Patrick McHardyd1db2752010-05-11 14:40:55 +020054struct ip6mr_rule {
55 struct fib_rule common;
56};
57
58struct ip6mr_result {
Yuval Mintzb70432f2018-02-28 23:29:32 +020059 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +020060};
61
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090062/* Big lock, protecting vif table, mrt cache and mroute socket state.
63 Note that the changes are semaphored via rtnl_lock.
64 */
65
66static DEFINE_RWLOCK(mrt_lock);
67
Yuval Mintzb70432f2018-02-28 23:29:32 +020068/* Multicast router control variables */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090069
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090070/* Special spinlock for queue of unresolved entries */
71static DEFINE_SPINLOCK(mfc_unres_lock);
72
73/* We return to original Alan's scheme. Hash table of resolved
74 entries is changed only in process context and protected
75 with weak lock mrt_lock. Queue of unresolved entries is protected
76 with strong spinlock mfc_unres_lock.
77
78 In this case data path is free of exclusive locks at all.
79 */
80
81static struct kmem_cache *mrt_cachep __read_mostly;
82
Yuval Mintzb70432f2018-02-28 23:29:32 +020083static struct mr_table *ip6mr_new_table(struct net *net, u32 id);
84static void ip6mr_free_table(struct mr_table *mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +020085
Yuval Mintzb70432f2018-02-28 23:29:32 +020086static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Rami Rosen2b52c3a2013-07-21 03:00:31 +030087 struct sk_buff *skb, struct mfc6_cache *cache);
Yuval Mintzb70432f2018-02-28 23:29:32 +020088static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Benjamin Thery8229efd2008-12-10 16:30:15 -080089 mifi_t mifi, int assert);
Yuval Mintzb70432f2018-02-28 23:29:32 +020090static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +000091 int cmd);
Yuval Mintzb70432f2018-02-28 23:29:32 +020092static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
Patrick McHardy5b285ca2010-05-11 14:40:56 +020093static int ip6mr_rtm_dumproute(struct sk_buff *skb,
94 struct netlink_callback *cb);
Yuval Mintzb70432f2018-02-28 23:29:32 +020095static void mroute_clean_tables(struct mr_table *mrt, bool all);
Kees Cooke99e88a2017-10-16 14:43:17 -070096static void ipmr_expire_process(struct timer_list *t);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090097
Patrick McHardyd1db2752010-05-11 14:40:55 +020098#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
Eric Dumazet8ffb3352010-06-06 15:34:40 -070099#define ip6mr_for_each_table(mrt, net) \
Patrick McHardyd1db2752010-05-11 14:40:55 +0200100 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
101
Yuval Mintz7b0db852018-02-28 23:29:39 +0200102static struct mr_table *ip6mr_mr_table_iter(struct net *net,
103 struct mr_table *mrt)
104{
105 struct mr_table *ret;
106
107 if (!mrt)
108 ret = list_entry_rcu(net->ipv6.mr6_tables.next,
109 struct mr_table, list);
110 else
111 ret = list_entry_rcu(mrt->list.next,
112 struct mr_table, list);
113
114 if (&ret->list == &net->ipv6.mr6_tables)
115 return NULL;
116 return ret;
117}
118
Yuval Mintzb70432f2018-02-28 23:29:32 +0200119static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200120{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200121 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200122
123 ip6mr_for_each_table(mrt, net) {
124 if (mrt->id == id)
125 return mrt;
126 }
127 return NULL;
128}
129
David S. Miller4c9483b2011-03-12 16:22:43 -0500130static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200131 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200132{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200133 int err;
Hannes Frederic Sowa95f4a452014-01-13 02:45:22 +0100134 struct ip6mr_result res;
135 struct fib_lookup_arg arg = {
136 .result = &res,
137 .flags = FIB_LOOKUP_NOREF,
138 };
Patrick McHardyd1db2752010-05-11 14:40:55 +0200139
David S. Miller4c9483b2011-03-12 16:22:43 -0500140 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
141 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200142 if (err < 0)
143 return err;
144 *mrt = res.mrt;
145 return 0;
146}
147
148static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
149 int flags, struct fib_lookup_arg *arg)
150{
151 struct ip6mr_result *res = arg->result;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200152 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200153
154 switch (rule->action) {
155 case FR_ACT_TO_TBL:
156 break;
157 case FR_ACT_UNREACHABLE:
158 return -ENETUNREACH;
159 case FR_ACT_PROHIBIT:
160 return -EACCES;
161 case FR_ACT_BLACKHOLE:
162 default:
163 return -EINVAL;
164 }
165
166 mrt = ip6mr_get_table(rule->fr_net, rule->table);
Ian Morris63159f22015-03-29 14:00:04 +0100167 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200168 return -EAGAIN;
169 res->mrt = mrt;
170 return 0;
171}
172
173static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
174{
175 return 1;
176}
177
178static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
179 FRA_GENERIC_POLICY,
180};
181
182static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
Roopa Prabhub16fb412018-04-21 09:41:31 -0700183 struct fib_rule_hdr *frh, struct nlattr **tb,
184 struct netlink_ext_ack *extack)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200185{
186 return 0;
187}
188
189static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
190 struct nlattr **tb)
191{
192 return 1;
193}
194
195static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
196 struct fib_rule_hdr *frh)
197{
198 frh->dst_len = 0;
199 frh->src_len = 0;
200 frh->tos = 0;
201 return 0;
202}
203
Andi Kleen04a6f822012-10-04 17:12:11 -0700204static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200205 .family = RTNL_FAMILY_IP6MR,
206 .rule_size = sizeof(struct ip6mr_rule),
207 .addr_size = sizeof(struct in6_addr),
208 .action = ip6mr_rule_action,
209 .match = ip6mr_rule_match,
210 .configure = ip6mr_rule_configure,
211 .compare = ip6mr_rule_compare,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200212 .fill = ip6mr_rule_fill,
213 .nlgroup = RTNLGRP_IPV6_RULE,
214 .policy = ip6mr_rule_policy,
215 .owner = THIS_MODULE,
216};
217
218static int __net_init ip6mr_rules_init(struct net *net)
219{
220 struct fib_rules_ops *ops;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200221 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200222 int err;
223
224 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
225 if (IS_ERR(ops))
226 return PTR_ERR(ops);
227
228 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
229
230 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
Sabrina Dubrocae783bb02018-06-05 15:02:00 +0200231 if (IS_ERR(mrt)) {
232 err = PTR_ERR(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200233 goto err1;
234 }
235
236 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
237 if (err < 0)
238 goto err2;
239
240 net->ipv6.mr6_rules_ops = ops;
241 return 0;
242
243err2:
WANG Congf243e5a2015-03-25 14:45:03 -0700244 ip6mr_free_table(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200245err1:
246 fib_rules_unregister(ops);
247 return err;
248}
249
250static void __net_exit ip6mr_rules_exit(struct net *net)
251{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200252 struct mr_table *mrt, *next;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200253
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200254 rtnl_lock();
Eric Dumazet035320d2010-06-06 23:48:40 +0000255 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
256 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200257 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000258 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200259 fib_rules_unregister(net->ipv6.mr6_rules_ops);
WANG Cong419df122015-03-31 11:01:46 -0700260 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200261}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300262
263static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
264{
265 return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR);
266}
267
268static unsigned int ip6mr_rules_seq_read(struct net *net)
269{
270 return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
271}
Yuval Mintzd3c07e52018-03-26 15:01:35 +0300272
273bool ip6mr_rule_default(const struct fib_rule *rule)
274{
275 return fib_rule_matchall(rule) && rule->action == FR_ACT_TO_TBL &&
276 rule->table == RT6_TABLE_DFLT && !rule->l3mdev;
277}
278EXPORT_SYMBOL(ip6mr_rule_default);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200279#else
280#define ip6mr_for_each_table(mrt, net) \
281 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
282
Yuval Mintz7b0db852018-02-28 23:29:39 +0200283static struct mr_table *ip6mr_mr_table_iter(struct net *net,
284 struct mr_table *mrt)
285{
286 if (!mrt)
287 return net->ipv6.mrt6;
288 return NULL;
289}
290
Yuval Mintzb70432f2018-02-28 23:29:32 +0200291static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200292{
293 return net->ipv6.mrt6;
294}
295
David S. Miller4c9483b2011-03-12 16:22:43 -0500296static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200297 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200298{
299 *mrt = net->ipv6.mrt6;
300 return 0;
301}
302
303static int __net_init ip6mr_rules_init(struct net *net)
304{
Sabrina Dubrocae783bb02018-06-05 15:02:00 +0200305 struct mr_table *mrt;
306
307 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
308 if (IS_ERR(mrt))
309 return PTR_ERR(mrt);
310 net->ipv6.mrt6 = mrt;
311 return 0;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200312}
313
314static void __net_exit ip6mr_rules_exit(struct net *net)
315{
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200316 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200317 ip6mr_free_table(net->ipv6.mrt6);
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200318 net->ipv6.mrt6 = NULL;
319 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200320}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300321
322static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
323{
324 return 0;
325}
326
327static unsigned int ip6mr_rules_seq_read(struct net *net)
328{
329 return 0;
330}
Patrick McHardyd1db2752010-05-11 14:40:55 +0200331#endif
332
Yuval Mintz87c418b2018-02-28 23:29:31 +0200333static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
334 const void *ptr)
335{
336 const struct mfc6_cache_cmp_arg *cmparg = arg->key;
337 struct mfc6_cache *c = (struct mfc6_cache *)ptr;
338
339 return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) ||
340 !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin);
341}
342
343static const struct rhashtable_params ip6mr_rht_params = {
Yuval Mintz494fff52018-02-28 23:29:34 +0200344 .head_offset = offsetof(struct mr_mfc, mnode),
Yuval Mintz87c418b2018-02-28 23:29:31 +0200345 .key_offset = offsetof(struct mfc6_cache, cmparg),
346 .key_len = sizeof(struct mfc6_cache_cmp_arg),
347 .nelem_hint = 3,
348 .locks_mul = 1,
349 .obj_cmpfn = ip6mr_hash_cmp,
350 .automatic_shrinking = true,
351};
352
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200353static void ip6mr_new_table_set(struct mr_table *mrt,
354 struct net *net)
355{
356#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
357 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
358#endif
359}
360
Yuval Mintz845c9a72018-02-28 23:29:35 +0200361static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = {
362 .mf6c_origin = IN6ADDR_ANY_INIT,
363 .mf6c_mcastgrp = IN6ADDR_ANY_INIT,
364};
365
366static struct mr_table_ops ip6mr_mr_table_ops = {
367 .rht_params = &ip6mr_rht_params,
368 .cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
369};
370
Yuval Mintzb70432f2018-02-28 23:29:32 +0200371static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200372{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200373 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200374
375 mrt = ip6mr_get_table(net, id);
Ian Morris53b24b82015-03-29 14:00:05 +0100376 if (mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200377 return mrt;
378
Yuval Mintz845c9a72018-02-28 23:29:35 +0200379 return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200380 ipmr_expire_process, ip6mr_new_table_set);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200381}
382
Yuval Mintzb70432f2018-02-28 23:29:32 +0200383static void ip6mr_free_table(struct mr_table *mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200384{
WANG Cong7ba0c472015-03-31 11:01:47 -0700385 del_timer_sync(&mrt->ipmr_expire_timer);
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +0100386 mroute_clean_tables(mrt, true);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200387 rhltable_destroy(&mrt->mfc_hash);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200388 kfree(mrt);
389}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900390
391#ifdef CONFIG_PROC_FS
Yuval Mintzc8d61962018-02-28 23:29:36 +0200392/* The /proc interfaces to multicast routing
393 * /proc/ip6_mr_cache /proc/ip6_mr_vif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900394 */
395
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900396static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
397 __acquires(mrt_lock)
398{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200399 struct mr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800400 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200401 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200402
403 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100404 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200405 return ERR_PTR(-ENOENT);
406
407 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800408
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900409 read_lock(&mrt_lock);
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200410 return mr_vif_seq_start(seq, pos);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900411}
412
413static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
414 __releases(mrt_lock)
415{
416 read_unlock(&mrt_lock);
417}
418
419static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
420{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200421 struct mr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200422 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800423
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900424 if (v == SEQ_START_TOKEN) {
425 seq_puts(seq,
426 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
427 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200428 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900429 const char *name = vif->dev ? vif->dev->name : "none";
430
431 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100432 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200433 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900434 name, vif->bytes_in, vif->pkt_in,
435 vif->bytes_out, vif->pkt_out,
436 vif->flags);
437 }
438 return 0;
439}
440
Stephen Hemminger98147d52009-09-01 19:25:02 +0000441static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900442 .start = ip6mr_vif_seq_start,
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200443 .next = mr_vif_seq_next,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900444 .stop = ip6mr_vif_seq_stop,
445 .show = ip6mr_vif_seq_show,
446};
447
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900448static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
449{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800450 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200451 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800452
Patrick McHardyd1db2752010-05-11 14:40:55 +0200453 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100454 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200455 return ERR_PTR(-ENOENT);
456
Yuval Mintzc8d61962018-02-28 23:29:36 +0200457 return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900458}
459
460static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
461{
462 int n;
463
464 if (v == SEQ_START_TOKEN) {
465 seq_puts(seq,
466 "Group "
467 "Origin "
468 "Iif Pkts Bytes Wrong Oifs\n");
469 } else {
470 const struct mfc6_cache *mfc = v;
Yuval Mintzc8d61962018-02-28 23:29:36 +0200471 const struct mr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200472 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900473
Benjamin Thery999890b2008-12-03 22:22:16 -0800474 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700475 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200476 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900477
Yuval Mintzb70432f2018-02-28 23:29:32 +0200478 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800479 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200480 mfc->_c.mfc_un.res.pkt,
481 mfc->_c.mfc_un.res.bytes,
482 mfc->_c.mfc_un.res.wrong_if);
483 for (n = mfc->_c.mfc_un.res.minvif;
484 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200485 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200486 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900487 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200488 " %2d:%-3d", n,
489 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900490 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800491 } else {
492 /* unresolved mfc_caches don't contain
493 * pkt, bytes and wrong_if values
494 */
495 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900496 }
497 seq_putc(seq, '\n');
498 }
499 return 0;
500}
501
James Morris88e9d342009-09-22 16:43:43 -0700502static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900503 .start = ipmr_mfc_seq_start,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200504 .next = mr_mfc_seq_next,
505 .stop = mr_mfc_seq_stop,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900506 .show = ipmr_mfc_seq_show,
507};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900508#endif
509
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900510#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900511
512static int pim6_rcv(struct sk_buff *skb)
513{
514 struct pimreghdr *pim;
515 struct ipv6hdr *encap;
516 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800517 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200518 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500519 struct flowi6 fl6 = {
520 .flowi6_iif = skb->dev->ifindex,
521 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200522 };
523 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900524
525 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
526 goto drop;
527
528 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100529 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900530 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800531 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
532 sizeof(*pim), IPPROTO_PIM,
533 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700534 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900535 goto drop;
536
537 /* check if the inner packet is destined to mcast group */
538 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
539 sizeof(*pim));
540
541 if (!ipv6_addr_is_multicast(&encap->daddr) ||
542 encap->payload_len == 0 ||
543 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
544 goto drop;
545
David S. Miller4c9483b2011-03-12 16:22:43 -0500546 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200547 goto drop;
548 reg_vif_num = mrt->mroute_reg_vif_num;
549
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900550 read_lock(&mrt_lock);
551 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200552 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900553 if (reg_dev)
554 dev_hold(reg_dev);
555 read_unlock(&mrt_lock);
556
Ian Morris63159f22015-03-29 14:00:04 +0100557 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900558 goto drop;
559
560 skb->mac_header = skb->network_header;
561 skb_pull(skb, (u8 *)encap - skb->data);
562 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800563 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000564 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700565
Nicolas Dichtelea231922013-09-02 15:34:58 +0200566 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700567
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000568 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000569
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900570 dev_put(reg_dev);
571 return 0;
572 drop:
573 kfree_skb(skb);
574 return 0;
575}
576
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000577static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900578 .handler = pim6_rcv,
579};
580
581/* Service routines creating virtual interfaces: PIMREG */
582
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000583static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
584 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900585{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800586 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200587 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500588 struct flowi6 fl6 = {
589 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700590 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500591 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200592 };
593 int err;
594
David S. Miller4c9483b2011-03-12 16:22:43 -0500595 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000596 if (err < 0) {
597 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200598 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000599 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800600
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900601 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700602 dev->stats.tx_bytes += skb->len;
603 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200604 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900605 read_unlock(&mrt_lock);
606 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000607 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900608}
609
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200610static int reg_vif_get_iflink(const struct net_device *dev)
611{
612 return 0;
613}
614
Stephen Hemminger007c3832008-11-20 20:28:35 -0800615static const struct net_device_ops reg_vif_netdev_ops = {
616 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200617 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800618};
619
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900620static void reg_vif_setup(struct net_device *dev)
621{
622 dev->type = ARPHRD_PIMREG;
623 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
624 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800625 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400626 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700627 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900628}
629
Yuval Mintzb70432f2018-02-28 23:29:32 +0200630static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900631{
632 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200633 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900634
Patrick McHardyd1db2752010-05-11 14:40:55 +0200635 if (mrt->id == RT6_TABLE_DFLT)
636 sprintf(name, "pim6reg");
637 else
638 sprintf(name, "pim6reg%u", mrt->id);
639
Tom Gundersenc835a672014-07-14 16:37:24 +0200640 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100641 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900642 return NULL;
643
Benjamin Thery8229efd2008-12-10 16:30:15 -0800644 dev_net_set(dev, net);
645
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900646 if (register_netdevice(dev)) {
647 free_netdev(dev);
648 return NULL;
649 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900650
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900651 if (dev_open(dev))
652 goto failure;
653
Wang Chen7af3db72008-07-14 20:54:54 -0700654 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900655 return dev;
656
657failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900658 unregister_netdevice(dev);
659 return NULL;
660}
661#endif
662
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300663static int call_ip6mr_vif_entry_notifiers(struct net *net,
664 enum fib_event_type event_type,
665 struct vif_device *vif,
666 mifi_t vif_index, u32 tb_id)
667{
668 return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
669 vif, vif_index, tb_id,
670 &net->ipv6.ipmr_seq);
671}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900672
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300673static int call_ip6mr_mfc_entry_notifiers(struct net *net,
674 enum fib_event_type event_type,
675 struct mfc6_cache *mfc, u32 tb_id)
676{
677 return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
678 &mfc->_c, tb_id, &net->ipv6.ipmr_seq);
679}
680
681/* Delete a VIF entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200682static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300683 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900684{
Yuval Mintz6853f212018-02-28 23:29:29 +0200685 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900686 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800687 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200688
689 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900690 return -EADDRNOTAVAIL;
691
Yuval Mintzb70432f2018-02-28 23:29:32 +0200692 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900693
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300694 if (VIF_EXISTS(mrt, vifi))
695 call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
696 FIB_EVENT_VIF_DEL, v, vifi,
697 mrt->id);
698
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900699 write_lock_bh(&mrt_lock);
700 dev = v->dev;
701 v->dev = NULL;
702
703 if (!dev) {
704 write_unlock_bh(&mrt_lock);
705 return -EADDRNOTAVAIL;
706 }
707
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900708#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200709 if (vifi == mrt->mroute_reg_vif_num)
710 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900711#endif
712
Patrick McHardy6bd52142010-05-11 14:40:53 +0200713 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900714 int tmp;
715 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200716 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900717 break;
718 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200719 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900720 }
721
722 write_unlock_bh(&mrt_lock);
723
724 dev_set_allmulti(dev, -1);
725
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800726 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000727 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800728 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700729 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000730 NETCONFA_MC_FORWARDING,
731 dev->ifindex, &in6_dev->cnf);
732 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800733
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300734 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000735 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900736
737 dev_put(dev);
738 return 0;
739}
740
Yuval Mintz87c418b2018-02-28 23:29:31 +0200741static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
742{
Yuval Mintz494fff52018-02-28 23:29:34 +0200743 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200744
Yuval Mintz494fff52018-02-28 23:29:34 +0200745 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200746}
747
Benjamin Thery58701ad2008-12-10 16:22:34 -0800748static inline void ip6mr_cache_free(struct mfc6_cache *c)
749{
Yuval Mintz494fff52018-02-28 23:29:34 +0200750 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800751}
752
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900753/* Destroy an unresolved cache entry, killing queued skbs
754 and reporting error to netlink readers.
755 */
756
Yuval Mintzb70432f2018-02-28 23:29:32 +0200757static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900758{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200759 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900760 struct sk_buff *skb;
761
Patrick McHardy6bd52142010-05-11 14:40:53 +0200762 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900763
Yuval Mintz494fff52018-02-28 23:29:34 +0200764 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900765 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200766 struct nlmsghdr *nlh = skb_pull(skb,
767 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900768 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000769 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900770 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000771 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000772 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900773 } else
774 kfree_skb(skb);
775 }
776
Benjamin Thery58701ad2008-12-10 16:22:34 -0800777 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900778}
779
780
Patrick McHardyc476efb2010-05-11 14:40:48 +0200781/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900782
Yuval Mintzb70432f2018-02-28 23:29:32 +0200783static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900784{
785 unsigned long now = jiffies;
786 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200787 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900788
Yuval Mintzb70432f2018-02-28 23:29:32 +0200789 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900790 if (time_after(c->mfc_un.unres.expires, now)) {
791 /* not yet... */
792 unsigned long interval = c->mfc_un.unres.expires - now;
793 if (interval < expires)
794 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900795 continue;
796 }
797
Patrick McHardyf30a77842010-05-11 14:40:51 +0200798 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200799 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
800 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900801 }
802
Yuval Mintzb70432f2018-02-28 23:29:32 +0200803 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200804 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900805}
806
Kees Cooke99e88a2017-10-16 14:43:17 -0700807static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900808{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200809 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200810
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900811 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200812 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900813 return;
814 }
815
Yuval Mintzb70432f2018-02-28 23:29:32 +0200816 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200817 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900818
819 spin_unlock(&mfc_unres_lock);
820}
821
822/* Fill oifs list. It is called under write locked mrt_lock. */
823
Yuval Mintzb70432f2018-02-28 23:29:32 +0200824static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200825 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200826 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900827{
828 int vifi;
829
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300830 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900831 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300832 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900833
Patrick McHardy6bd52142010-05-11 14:40:53 +0200834 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200835 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800836 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900837 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
838 if (cache->mfc_un.res.minvif > vifi)
839 cache->mfc_un.res.minvif = vifi;
840 if (cache->mfc_un.res.maxvif <= vifi)
841 cache->mfc_un.res.maxvif = vifi + 1;
842 }
843 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200844 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900845}
846
Yuval Mintzb70432f2018-02-28 23:29:32 +0200847static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200848 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900849{
850 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200851 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900852 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800853 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700854 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900855
856 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200857 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900858 return -EADDRINUSE;
859
860 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900861#ifdef CONFIG_IPV6_PIMSM_V2
862 case MIFF_REGISTER:
863 /*
864 * Special Purpose VIF in PIM
865 * All the packets will be sent to the daemon
866 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200867 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900868 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200869 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900870 if (!dev)
871 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700872 err = dev_set_allmulti(dev, 1);
873 if (err) {
874 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700875 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700876 return err;
877 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900878 break;
879#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900880 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800881 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900882 if (!dev)
883 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700884 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700885 if (err) {
886 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700887 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700888 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900889 break;
890 default:
891 return -EINVAL;
892 }
893
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800894 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000895 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800896 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700897 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000898 NETCONFA_MC_FORWARDING,
899 dev->ifindex, &in6_dev->cnf);
900 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800901
Yuval Mintz6853f212018-02-28 23:29:29 +0200902 /* Fill in the VIF structures */
903 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
904 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
905 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900906
907 /* And finish update writing critical data */
908 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900909 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900910#ifdef CONFIG_IPV6_PIMSM_V2
911 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200912 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900913#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200914 if (vifi + 1 > mrt->maxvif)
915 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900916 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300917 call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
918 v, vifi, mrt->id);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900919 return 0;
920}
921
Yuval Mintzb70432f2018-02-28 23:29:32 +0200922static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000923 const struct in6_addr *origin,
924 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900925{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200926 struct mfc6_cache_cmp_arg arg = {
927 .mf6c_origin = *origin,
928 .mf6c_mcastgrp = *mcastgrp,
929 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900930
Yuval Mintz845c9a72018-02-28 23:29:35 +0200931 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000932}
933
934/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200935static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000936 struct in6_addr *mcastgrp,
937 mifi_t mifi)
938{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200939 struct mfc6_cache_cmp_arg arg = {
940 .mf6c_origin = in6addr_any,
941 .mf6c_mcastgrp = *mcastgrp,
942 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000943
944 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +0200945 return mr_mfc_find_any_parent(mrt, mifi);
946 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000947}
948
Yuval Mintz87c418b2018-02-28 23:29:31 +0200949/* Look for a (S,G,iif) entry if parent != -1 */
950static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +0200951ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +0200952 const struct in6_addr *origin,
953 const struct in6_addr *mcastgrp,
954 int parent)
955{
956 struct mfc6_cache_cmp_arg arg = {
957 .mf6c_origin = *origin,
958 .mf6c_mcastgrp = *mcastgrp,
959 };
Yuval Mintz87c418b2018-02-28 23:29:31 +0200960
Yuval Mintz845c9a72018-02-28 23:29:35 +0200961 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200962}
963
Yuval Mintz845c9a72018-02-28 23:29:35 +0200964/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200965static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900966{
Joe Perches36cbac52008-12-03 22:27:25 -0800967 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100968 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900969 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200970 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
971 c->_c.mfc_un.res.minvif = MAXMIFS;
Yuval Mintz8c13af22018-03-26 15:01:36 +0300972 c->_c.free = ip6mr_cache_free_rcu;
973 refcount_set(&c->_c.mfc_un.res.refcount, 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900974 return c;
975}
976
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200977static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900978{
Joe Perches36cbac52008-12-03 22:27:25 -0800979 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +0100980 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900981 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200982 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
983 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900984 return c;
985}
986
987/*
988 * A cache entry has gone into a resolved state from queued
989 */
990
Yuval Mintzb70432f2018-02-28 23:29:32 +0200991static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200992 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900993{
994 struct sk_buff *skb;
995
996 /*
997 * Play the pending entries through our router
998 */
999
Yuval Mintz494fff52018-02-28 23:29:34 +02001000 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001001 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +02001002 struct nlmsghdr *nlh = skb_pull(skb,
1003 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001004
Yuval Mintz7b0db852018-02-28 23:29:39 +02001005 if (mr_fill_mroute(mrt, skb, &c->_c,
1006 nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001007 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001008 } else {
1009 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +00001010 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001011 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +00001012 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001013 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001014 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001015 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001016 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001017 }
1018}
1019
1020/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001021 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001022 *
1023 * Called under mrt_lock.
1024 */
1025
Yuval Mintzb70432f2018-02-28 23:29:32 +02001026static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001027 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001028{
Yuval Mintz8571ab42018-02-28 23:29:30 +02001029 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001030 struct sk_buff *skb;
1031 struct mrt6msg *msg;
1032 int ret;
1033
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001034#ifdef CONFIG_IPV6_PIMSM_V2
1035 if (assert == MRT6MSG_WHOLEPKT)
1036 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1037 +sizeof(*msg));
1038 else
1039#endif
1040 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001041
1042 if (!skb)
1043 return -ENOBUFS;
1044
1045 /* I suppose that internal messages
1046 * do not require checksums */
1047
1048 skb->ip_summed = CHECKSUM_UNNECESSARY;
1049
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001050#ifdef CONFIG_IPV6_PIMSM_V2
1051 if (assert == MRT6MSG_WHOLEPKT) {
1052 /* Ugly, but we have no choice with this interface.
1053 Duplicate old header, fix length etc.
1054 And all this only to mangle msg->im6_msgtype and
1055 to set msg->im6_mbz to "mbz" :-)
1056 */
1057 skb_push(skb, -skb_network_offset(pkt));
1058
1059 skb_push(skb, sizeof(*msg));
1060 skb_reset_transport_header(skb);
1061 msg = (struct mrt6msg *)skb_transport_header(skb);
1062 msg->im6_mbz = 0;
1063 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001064 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001065 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001066 msg->im6_src = ipv6_hdr(pkt)->saddr;
1067 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001068
1069 skb->ip_summed = CHECKSUM_UNNECESSARY;
1070 } else
1071#endif
1072 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001073 /*
1074 * Copy the IP header
1075 */
1076
1077 skb_put(skb, sizeof(struct ipv6hdr));
1078 skb_reset_network_header(skb);
1079 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1080
1081 /*
1082 * Add our header
1083 */
1084 skb_put(skb, sizeof(*msg));
1085 skb_reset_transport_header(skb);
1086 msg = (struct mrt6msg *)skb_transport_header(skb);
1087
1088 msg->im6_mbz = 0;
1089 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001090 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001091 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001092 msg->im6_src = ipv6_hdr(pkt)->saddr;
1093 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001094
Eric Dumazetadf30902009-06-02 05:19:30 +00001095 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001096 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001097 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001098
Yuval Mintz8571ab42018-02-28 23:29:30 +02001099 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001100 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001101 if (!mroute6_sk) {
1102 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001103 kfree_skb(skb);
1104 return -EINVAL;
1105 }
1106
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001107 mrt6msg_netlink_event(mrt, skb);
1108
Yuval Mintz8571ab42018-02-28 23:29:30 +02001109 /* Deliver to user space multicast routing algorithms */
1110 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1111 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001112 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001113 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001114 kfree_skb(skb);
1115 }
1116
1117 return ret;
1118}
1119
Yuval Mintz494fff52018-02-28 23:29:34 +02001120/* Queue a packet for resolution. It gets locked cache entry! */
1121static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
1122 struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001123{
Yuval Mintz494fff52018-02-28 23:29:34 +02001124 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001125 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001126 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001127
1128 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001129 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001130 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001131 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1132 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001133 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001134 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001135 }
1136
Patrick McHardyf30a77842010-05-11 14:40:51 +02001137 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001138 /*
1139 * Create a new entry if allowable
1140 */
1141
Patrick McHardy6bd52142010-05-11 14:40:53 +02001142 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001143 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001144 spin_unlock_bh(&mfc_unres_lock);
1145
1146 kfree_skb(skb);
1147 return -ENOBUFS;
1148 }
1149
Yuval Mintz494fff52018-02-28 23:29:34 +02001150 /* Fill in the new cache entry */
1151 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001152 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1153 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1154
1155 /*
1156 * Reflect first query at pim6sd
1157 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001158 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001159 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001160 /* If the report failed throw the cache entry
1161 out - Brad Parker
1162 */
1163 spin_unlock_bh(&mfc_unres_lock);
1164
Benjamin Thery58701ad2008-12-10 16:22:34 -08001165 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001166 kfree_skb(skb);
1167 return err;
1168 }
1169
Patrick McHardy6bd52142010-05-11 14:40:53 +02001170 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001171 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001172 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001173
Patrick McHardy6bd52142010-05-11 14:40:53 +02001174 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001175 }
1176
Yuval Mintz494fff52018-02-28 23:29:34 +02001177 /* See if we can append the packet */
1178 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001179 kfree_skb(skb);
1180 err = -ENOBUFS;
1181 } else {
Yuval Mintz494fff52018-02-28 23:29:34 +02001182 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001183 err = 0;
1184 }
1185
1186 spin_unlock_bh(&mfc_unres_lock);
1187 return err;
1188}
1189
1190/*
1191 * MFC6 cache manipulation by user space
1192 */
1193
Yuval Mintzb70432f2018-02-28 23:29:32 +02001194static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001195 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001196{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001197 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001198
Yuval Mintz87c418b2018-02-28 23:29:31 +02001199 /* The entries are added/deleted only under RTNL */
1200 rcu_read_lock();
1201 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1202 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1203 rcu_read_unlock();
1204 if (!c)
1205 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001206 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1207 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001208
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001209 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1210 FIB_EVENT_ENTRY_DEL, c, mrt->id);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001211 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001212 mr_cache_put(&c->_c);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001213 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001214}
1215
1216static int ip6mr_device_event(struct notifier_block *this,
1217 unsigned long event, void *ptr)
1218{
Jiri Pirko351638e2013-05-28 01:30:21 +00001219 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001220 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001221 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001222 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001223 int ct;
1224
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001225 if (event != NETDEV_UNREGISTER)
1226 return NOTIFY_DONE;
1227
Patrick McHardyd1db2752010-05-11 14:40:55 +02001228 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001229 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001230 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1231 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001232 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001233 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001234 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001235
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001236 return NOTIFY_DONE;
1237}
1238
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001239static unsigned int ip6mr_seq_read(struct net *net)
1240{
1241 ASSERT_RTNL();
1242
1243 return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
1244}
1245
1246static int ip6mr_dump(struct net *net, struct notifier_block *nb)
1247{
1248 return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
1249 ip6mr_mr_table_iter, &mrt_lock);
1250}
1251
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001252static struct notifier_block ip6_mr_notifier = {
1253 .notifier_call = ip6mr_device_event
1254};
1255
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001256static const struct fib_notifier_ops ip6mr_notifier_ops_template = {
1257 .family = RTNL_FAMILY_IP6MR,
1258 .fib_seq_read = ip6mr_seq_read,
1259 .fib_dump = ip6mr_dump,
1260 .owner = THIS_MODULE,
1261};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001262
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001263static int __net_init ip6mr_notifier_init(struct net *net)
1264{
1265 struct fib_notifier_ops *ops;
1266
1267 net->ipv6.ipmr_seq = 0;
1268
1269 ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
1270 if (IS_ERR(ops))
1271 return PTR_ERR(ops);
1272
1273 net->ipv6.ip6mr_notifier_ops = ops;
1274
1275 return 0;
1276}
1277
1278static void __net_exit ip6mr_notifier_exit(struct net *net)
1279{
1280 fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops);
1281 net->ipv6.ip6mr_notifier_ops = NULL;
1282}
1283
1284/* Setup for IP multicast routing */
Benjamin Thery4e168802008-12-10 16:15:08 -08001285static int __net_init ip6mr_net_init(struct net *net)
1286{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001287 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001288
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001289 err = ip6mr_notifier_init(net);
1290 if (err)
1291 return err;
1292
Patrick McHardyd1db2752010-05-11 14:40:55 +02001293 err = ip6mr_rules_init(net);
1294 if (err < 0)
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001295 goto ip6mr_rules_fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001296
1297#ifdef CONFIG_PROC_FS
1298 err = -ENOMEM;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001299 if (!proc_create_net("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_seq_ops,
1300 sizeof(struct mr_vif_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001301 goto proc_vif_fail;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001302 if (!proc_create_net("ip6_mr_cache", 0, net->proc_net, &ipmr_mfc_seq_ops,
1303 sizeof(struct mr_mfc_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001304 goto proc_cache_fail;
1305#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001306
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001307 return 0;
1308
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001309#ifdef CONFIG_PROC_FS
1310proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001311 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001312proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001313 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001314#endif
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001315ip6mr_rules_fail:
1316 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001317 return err;
1318}
1319
1320static void __net_exit ip6mr_net_exit(struct net *net)
1321{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001322#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001323 remove_proc_entry("ip6_mr_cache", net->proc_net);
1324 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001325#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001326 ip6mr_rules_exit(net);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001327 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001328}
1329
1330static struct pernet_operations ip6mr_net_ops = {
1331 .init = ip6mr_net_init,
1332 .exit = ip6mr_net_exit,
1333};
1334
Wang Chen623d1a12008-07-03 12:13:30 +08001335int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001336{
Wang Chen623d1a12008-07-03 12:13:30 +08001337 int err;
1338
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001339 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1340 sizeof(struct mfc6_cache),
1341 0, SLAB_HWCACHE_ALIGN,
1342 NULL);
1343 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001344 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001345
Benjamin Thery4e168802008-12-10 16:15:08 -08001346 err = register_pernet_subsys(&ip6mr_net_ops);
1347 if (err)
1348 goto reg_pernet_fail;
1349
Wang Chen623d1a12008-07-03 12:13:30 +08001350 err = register_netdevice_notifier(&ip6_mr_notifier);
1351 if (err)
1352 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001353#ifdef CONFIG_IPV6_PIMSM_V2
1354 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001355 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001356 err = -EAGAIN;
1357 goto add_proto_fail;
1358 }
1359#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001360 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1361 NULL, ip6mr_rtm_dumproute, 0);
1362 if (err == 0)
1363 return 0;
1364
Tom Goff403dbb92009-06-14 03:16:13 -07001365#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001366 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001367add_proto_fail:
1368 unregister_netdevice_notifier(&ip6_mr_notifier);
1369#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001370reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001371 unregister_pernet_subsys(&ip6mr_net_ops);
1372reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001373 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001374 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001375}
1376
Wang Chen623d1a12008-07-03 12:13:30 +08001377void ip6_mr_cleanup(void)
1378{
Duan Jiongffb13882014-11-19 09:35:39 +08001379 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1380#ifdef CONFIG_IPV6_PIMSM_V2
1381 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1382#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001383 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001384 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001385 kmem_cache_destroy(mrt_cachep);
1386}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001387
Yuval Mintzb70432f2018-02-28 23:29:32 +02001388static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001389 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001390{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001391 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001392 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001393 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001394 bool found;
1395 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001396
Patrick McHardya50436f22010-03-17 06:04:14 +00001397 if (mfc->mf6cc_parent >= MAXMIFS)
1398 return -ENFILE;
1399
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001400 memset(ttls, 255, MAXMIFS);
1401 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001402 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1403 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001404 }
1405
Yuval Mintz87c418b2018-02-28 23:29:31 +02001406 /* The entries are added/deleted only under RTNL */
1407 rcu_read_lock();
1408 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1409 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1410 rcu_read_unlock();
1411 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001412 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001413 c->_c.mfc_parent = mfc->mf6cc_parent;
1414 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001415 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001416 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001417 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001418 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
1419 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001420 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001421 return 0;
1422 }
1423
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001424 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1425 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001426 return -EINVAL;
1427
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001428 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001429 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001430 return -ENOMEM;
1431
1432 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1433 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001434 c->_c.mfc_parent = mfc->mf6cc_parent;
1435 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001436 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001437 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001438
Yuval Mintz494fff52018-02-28 23:29:34 +02001439 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001440 ip6mr_rht_params);
1441 if (err) {
1442 pr_err("ip6mr: rhtable insert error %d\n", err);
1443 ip6mr_cache_free(c);
1444 return err;
1445 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001446 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001447
Yuval Mintz87c418b2018-02-28 23:29:31 +02001448 /* Check to see if we resolved a queued list. If so we
1449 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001450 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001451 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001452 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001453 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1454 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001455 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001456 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001457 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001458 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001459 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001460 break;
1461 }
1462 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001463 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001464 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001465 spin_unlock_bh(&mfc_unres_lock);
1466
Patrick McHardyf30a77842010-05-11 14:40:51 +02001467 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001468 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001469 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001470 }
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001471 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
1472 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001473 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001474 return 0;
1475}
1476
1477/*
1478 * Close the multicast socket, and clear the vif tables etc
1479 */
1480
Yuval Mintzb70432f2018-02-28 23:29:32 +02001481static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001482{
Yuval Mintz494fff52018-02-28 23:29:34 +02001483 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001484 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001485 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001486
Yuval Mintz87c418b2018-02-28 23:29:31 +02001487 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001488 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001489 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001490 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001491 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001492 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001493 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001494
Yuval Mintz87c418b2018-02-28 23:29:31 +02001495 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001496 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001497 if (!all && (c->mfc_flags & MFC_STATIC))
1498 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001499 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001500 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001501 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001502 mr_cache_put(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001503 }
1504
Patrick McHardy6bd52142010-05-11 14:40:53 +02001505 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001506 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001507 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001508 list_del(&c->list);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001509 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1510 FIB_EVENT_ENTRY_DEL,
1511 (struct mfc6_cache *)c,
1512 mrt->id);
Yuval Mintz494fff52018-02-28 23:29:34 +02001513 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1514 RTM_DELROUTE);
1515 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001516 }
1517 spin_unlock_bh(&mfc_unres_lock);
1518 }
1519}
1520
Yuval Mintzb70432f2018-02-28 23:29:32 +02001521static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001522{
1523 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001524 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001525
1526 rtnl_lock();
1527 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001528 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001529 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001530 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001531 rcu_assign_pointer(mrt->mroute_sk, sk);
Eric Dumazeta366e302018-03-07 08:43:19 -08001532 sock_set_flag(sk, SOCK_RCU_FREE);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001533 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001534 }
1535 write_unlock_bh(&mrt_lock);
1536
1537 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001538 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1539 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001540 NETCONFA_IFINDEX_ALL,
1541 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001542 rtnl_unlock();
1543
1544 return err;
1545}
1546
1547int ip6mr_sk_done(struct sock *sk)
1548{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001549 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001550 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001551 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001552
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001553 if (sk->sk_type != SOCK_RAW ||
1554 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1555 return err;
1556
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001557 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001558 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001559 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001560 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001561 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Eric Dumazeta366e302018-03-07 08:43:19 -08001562 /* Note that mroute_sk had SOCK_RCU_FREE set,
1563 * so the RCU grace period before sk freeing
1564 * is guaranteed by sk_destruct()
1565 */
Patrick McHardyd1db2752010-05-11 14:40:55 +02001566 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001567 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001568 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001569 NETCONFA_MC_FORWARDING,
1570 NETCONFA_IFINDEX_ALL,
1571 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001572
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001573 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001574 err = 0;
1575 break;
1576 }
1577 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001578 rtnl_unlock();
1579
1580 return err;
1581}
1582
Yuval Mintz8571ab42018-02-28 23:29:30 +02001583bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001584{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001585 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001586 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001587 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001588 .flowi6_oif = skb->dev->ifindex,
1589 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001590 };
1591
David S. Miller4c9483b2011-03-12 16:22:43 -05001592 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001593 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001594
Yuval Mintzb70432f2018-02-28 23:29:32 +02001595 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001596}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001597EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001598
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001599/*
1600 * Socket options and virtual interface manipulation. The whole
1601 * virtual interface system is a complete heap, but unfortunately
1602 * that's how BSD mrouted happens to think. Maybe one day with a proper
1603 * MOSPF/PIM router set up we can clean this up.
1604 */
1605
David S. Millerb7058842009-09-30 16:12:20 -07001606int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001607{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001608 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001609 struct mif6ctl vif;
1610 struct mf6cctl mfc;
1611 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001612 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001613 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001614
Xin Long99253eb2017-02-24 16:29:06 +08001615 if (sk->sk_type != SOCK_RAW ||
1616 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1617 return -EOPNOTSUPP;
1618
Patrick McHardyd1db2752010-05-11 14:40:55 +02001619 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001620 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001621 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001622
1623 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001624 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001625 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001626 return -EACCES;
1627 }
1628
1629 switch (optname) {
1630 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001631 if (optlen < sizeof(int))
1632 return -EINVAL;
1633
Patrick McHardy6bd52142010-05-11 14:40:53 +02001634 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001635
1636 case MRT6_DONE:
1637 return ip6mr_sk_done(sk);
1638
1639 case MRT6_ADD_MIF:
1640 if (optlen < sizeof(vif))
1641 return -EINVAL;
1642 if (copy_from_user(&vif, optval, sizeof(vif)))
1643 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001644 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001645 return -ENFILE;
1646 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001647 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001648 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001649 rtnl_unlock();
1650 return ret;
1651
1652 case MRT6_DEL_MIF:
1653 if (optlen < sizeof(mifi_t))
1654 return -EINVAL;
1655 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1656 return -EFAULT;
1657 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001658 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001659 rtnl_unlock();
1660 return ret;
1661
1662 /*
1663 * Manipulate the forwarding caches. These live
1664 * in a sort of kernel/user symbiosis.
1665 */
1666 case MRT6_ADD_MFC:
1667 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001668 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001669 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001670 case MRT6_ADD_MFC_PROXY:
1671 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001672 if (optlen < sizeof(mfc))
1673 return -EINVAL;
1674 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1675 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001676 if (parent == 0)
1677 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001678 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001679 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1680 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001681 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001682 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001683 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001684 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001685 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001686 rtnl_unlock();
1687 return ret;
1688
1689 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001690 * Control PIM assert (to activate pim will activate assert)
1691 */
1692 case MRT6_ASSERT:
1693 {
1694 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001695
1696 if (optlen != sizeof(v))
1697 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001698 if (get_user(v, (int __user *)optval))
1699 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001700 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001701 return 0;
1702 }
1703
1704#ifdef CONFIG_IPV6_PIMSM_V2
1705 case MRT6_PIM:
1706 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001707 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;
1713 v = !!v;
1714 rtnl_lock();
1715 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001716 if (v != mrt->mroute_do_pim) {
1717 mrt->mroute_do_pim = v;
1718 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001719 }
1720 rtnl_unlock();
1721 return ret;
1722 }
1723
1724#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001725#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1726 case MRT6_TABLE:
1727 {
1728 u32 v;
1729
1730 if (optlen != sizeof(u32))
1731 return -EINVAL;
1732 if (get_user(v, (u32 __user *)optval))
1733 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001734 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1735 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1736 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001737 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001738 return -EBUSY;
1739
1740 rtnl_lock();
1741 ret = 0;
Sabrina Dubrocae783bb02018-06-05 15:02:00 +02001742 mrt = ip6mr_new_table(net, v);
1743 if (IS_ERR(mrt))
1744 ret = PTR_ERR(mrt);
Sabrina Dubroca848235e2018-06-05 15:01:59 +02001745 else
1746 raw6_sk(sk)->ip6mr_table = v;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001747 rtnl_unlock();
1748 return ret;
1749 }
1750#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001751 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001752 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001753 * set.
1754 */
1755 default:
1756 return -ENOPROTOOPT;
1757 }
1758}
1759
1760/*
1761 * Getsock opt support for the multicast routing system.
1762 */
1763
1764int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1765 int __user *optlen)
1766{
1767 int olr;
1768 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001769 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001770 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001771
Xin Long99253eb2017-02-24 16:29:06 +08001772 if (sk->sk_type != SOCK_RAW ||
1773 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1774 return -EOPNOTSUPP;
1775
Patrick McHardyd1db2752010-05-11 14:40:55 +02001776 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001777 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001778 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001779
1780 switch (optname) {
1781 case MRT6_VERSION:
1782 val = 0x0305;
1783 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001784#ifdef CONFIG_IPV6_PIMSM_V2
1785 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001786 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001787 break;
1788#endif
1789 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001790 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001791 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001792 default:
1793 return -ENOPROTOOPT;
1794 }
1795
1796 if (get_user(olr, optlen))
1797 return -EFAULT;
1798
1799 olr = min_t(int, olr, sizeof(int));
1800 if (olr < 0)
1801 return -EINVAL;
1802
1803 if (put_user(olr, optlen))
1804 return -EFAULT;
1805 if (copy_to_user(optval, &val, olr))
1806 return -EFAULT;
1807 return 0;
1808}
1809
1810/*
1811 * The IP multicast ioctl support routines.
1812 */
1813
1814int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1815{
1816 struct sioc_sg_req6 sr;
1817 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001818 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001819 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001820 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001821 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001822
1823 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001824 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001825 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001826
1827 switch (cmd) {
1828 case SIOCGETMIFCNT_IN6:
1829 if (copy_from_user(&vr, arg, sizeof(vr)))
1830 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001831 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001832 return -EINVAL;
1833 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001834 vif = &mrt->vif_table[vr.mifi];
1835 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001836 vr.icount = vif->pkt_in;
1837 vr.ocount = vif->pkt_out;
1838 vr.ibytes = vif->bytes_in;
1839 vr.obytes = vif->bytes_out;
1840 read_unlock(&mrt_lock);
1841
1842 if (copy_to_user(arg, &vr, sizeof(vr)))
1843 return -EFAULT;
1844 return 0;
1845 }
1846 read_unlock(&mrt_lock);
1847 return -EADDRNOTAVAIL;
1848 case SIOCGETSGCNT_IN6:
1849 if (copy_from_user(&sr, arg, sizeof(sr)))
1850 return -EFAULT;
1851
Yuval Mintz87c418b2018-02-28 23:29:31 +02001852 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001853 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001854 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001855 sr.pktcnt = c->_c.mfc_un.res.pkt;
1856 sr.bytecnt = c->_c.mfc_un.res.bytes;
1857 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001858 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001859
1860 if (copy_to_user(arg, &sr, sizeof(sr)))
1861 return -EFAULT;
1862 return 0;
1863 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001864 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001865 return -EADDRNOTAVAIL;
1866 default:
1867 return -ENOIOCTLCMD;
1868 }
1869}
1870
David S. Millere2d57762011-02-03 17:59:32 -08001871#ifdef CONFIG_COMPAT
1872struct compat_sioc_sg_req6 {
1873 struct sockaddr_in6 src;
1874 struct sockaddr_in6 grp;
1875 compat_ulong_t pktcnt;
1876 compat_ulong_t bytecnt;
1877 compat_ulong_t wrong_if;
1878};
1879
1880struct compat_sioc_mif_req6 {
1881 mifi_t mifi;
1882 compat_ulong_t icount;
1883 compat_ulong_t ocount;
1884 compat_ulong_t ibytes;
1885 compat_ulong_t obytes;
1886};
1887
1888int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1889{
1890 struct compat_sioc_sg_req6 sr;
1891 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001892 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001893 struct mfc6_cache *c;
1894 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001895 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001896
1897 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001898 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001899 return -ENOENT;
1900
1901 switch (cmd) {
1902 case SIOCGETMIFCNT_IN6:
1903 if (copy_from_user(&vr, arg, sizeof(vr)))
1904 return -EFAULT;
1905 if (vr.mifi >= mrt->maxvif)
1906 return -EINVAL;
1907 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001908 vif = &mrt->vif_table[vr.mifi];
1909 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001910 vr.icount = vif->pkt_in;
1911 vr.ocount = vif->pkt_out;
1912 vr.ibytes = vif->bytes_in;
1913 vr.obytes = vif->bytes_out;
1914 read_unlock(&mrt_lock);
1915
1916 if (copy_to_user(arg, &vr, sizeof(vr)))
1917 return -EFAULT;
1918 return 0;
1919 }
1920 read_unlock(&mrt_lock);
1921 return -EADDRNOTAVAIL;
1922 case SIOCGETSGCNT_IN6:
1923 if (copy_from_user(&sr, arg, sizeof(sr)))
1924 return -EFAULT;
1925
Yuval Mintz87c418b2018-02-28 23:29:31 +02001926 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001927 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1928 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001929 sr.pktcnt = c->_c.mfc_un.res.pkt;
1930 sr.bytecnt = c->_c.mfc_un.res.bytes;
1931 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001932 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001933
1934 if (copy_to_user(arg, &sr, sizeof(sr)))
1935 return -EFAULT;
1936 return 0;
1937 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001938 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001939 return -EADDRNOTAVAIL;
1940 default:
1941 return -ENOIOCTLCMD;
1942 }
1943}
1944#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001945
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001946static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001947{
Eric Dumazet1d015502016-04-27 16:44:40 -07001948 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1949 IPSTATS_MIB_OUTFORWDATAGRAMS);
1950 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1951 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001952 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001953}
1954
1955/*
1956 * Processing handlers for ip6mr_forward
1957 */
1958
Yuval Mintzb70432f2018-02-28 23:29:32 +02001959static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001960 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001961{
1962 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001963 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001964 struct net_device *dev;
1965 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001966 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001967
Ian Morris63159f22015-03-29 14:00:04 +01001968 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001969 goto out_free;
1970
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001971#ifdef CONFIG_IPV6_PIMSM_V2
1972 if (vif->flags & MIFF_REGISTER) {
1973 vif->pkt_out++;
1974 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001975 vif->dev->stats.tx_bytes += skb->len;
1976 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001977 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001978 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001979 }
1980#endif
1981
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001982 ipv6h = ipv6_hdr(skb);
1983
David S. Miller4c9483b2011-03-12 16:22:43 -05001984 fl6 = (struct flowi6) {
1985 .flowi6_oif = vif->link,
1986 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001987 };
1988
David S. Miller4c9483b2011-03-12 16:22:43 -05001989 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001990 if (dst->error) {
1991 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001992 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00001993 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001994
Eric Dumazetadf30902009-06-02 05:19:30 +00001995 skb_dst_drop(skb);
1996 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001997
1998 /*
1999 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2000 * not only before forwarding, but after forwarding on all output
2001 * interfaces. It is clear, if mrouter runs a multicasting
2002 * program, it should receive packets not depending to what interface
2003 * program is joined.
2004 * If we will not make it, the program will have to join on all
2005 * interfaces. On the other hand, multihoming host (or router, but
2006 * not mrouter) cannot join to more than one interface - it will
2007 * result in receiving multiple packets.
2008 */
2009 dev = vif->dev;
2010 skb->dev = dev;
2011 vif->pkt_out++;
2012 vif->bytes_out += skb->len;
2013
2014 /* We are about to write */
2015 /* XXX: extension headers? */
2016 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2017 goto out_free;
2018
2019 ipv6h = ipv6_hdr(skb);
2020 ipv6h->hop_limit--;
2021
2022 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2023
Eric W. Biederman29a26a52015-09-15 20:04:16 -05002024 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
2025 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002026 ip6mr_forward2_finish);
2027
2028out_free:
2029 kfree_skb(skb);
2030 return 0;
2031}
2032
Yuval Mintzb70432f2018-02-28 23:29:32 +02002033static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002034{
2035 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002036
2037 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02002038 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002039 break;
2040 }
2041 return ct;
2042}
2043
Yuval Mintzb70432f2018-02-28 23:29:32 +02002044static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +02002045 struct sk_buff *skb, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002046{
2047 int psend = -1;
2048 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002049 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002050
Yuval Mintz494fff52018-02-28 23:29:34 +02002051 vif = c->_c.mfc_parent;
2052 c->_c.mfc_un.res.pkt++;
2053 c->_c.mfc_un.res.bytes += skb->len;
2054 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002055
Yuval Mintz494fff52018-02-28 23:29:34 +02002056 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002057 struct mfc6_cache *cache_proxy;
2058
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01002059 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002060 * interface is part of the static tree.
2061 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02002062 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02002063 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002064 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002065 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002066 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002067 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02002068 }
2069 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002070 }
2071
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002072 /*
2073 * Wrong interface: drop packet and (maybe) send PIM assert.
2074 */
Yuval Mintzb70432f2018-02-28 23:29:32 +02002075 if (mrt->vif_table[vif].dev != skb->dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002076 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002077
Patrick McHardy6bd52142010-05-11 14:40:53 +02002078 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002079 /* pimsm uses asserts, when switching from RPT to SPT,
2080 so that we cannot check that packet arrived on an oif.
2081 It is bad, but otherwise we would need to move pretty
2082 large chunk of pimd to kernel. Ough... --ANK
2083 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002084 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02002085 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002086 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02002087 c->_c.mfc_un.res.last_assert +
2088 MFC_ASSERT_THRESH)) {
2089 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002090 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002091 }
2092 goto dont_forward;
2093 }
2094
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002095forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02002096 mrt->vif_table[vif].pkt_in++;
2097 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002098
2099 /*
2100 * Forward the frame
2101 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002102 if (ipv6_addr_any(&c->mf6c_origin) &&
2103 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002104 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002105 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002106 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02002107 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002108 /* It's an (*,*) entry and the packet is not coming from
2109 * the upstream: forward the packet to the upstream
2110 * only.
2111 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002112 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002113 goto last_forward;
2114 }
2115 goto dont_forward;
2116 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002117 for (ct = c->_c.mfc_un.res.maxvif - 1;
2118 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002119 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002120 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2121 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002122 if (psend != -1) {
2123 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2124 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002125 ip6mr_forward2(net, mrt, skb2,
2126 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002127 }
2128 psend = ct;
2129 }
2130 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002131last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002132 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002133 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002134 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002135 }
2136
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002137dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002138 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002139}
2140
2141
2142/*
2143 * Multicast packets for forwarding arrive here
2144 */
2145
2146int ip6_mr_input(struct sk_buff *skb)
2147{
2148 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002149 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002150 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002151 struct flowi6 fl6 = {
2152 .flowi6_iif = skb->dev->ifindex,
2153 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002154 };
2155 int err;
2156
David S. Miller4c9483b2011-03-12 16:22:43 -05002157 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002158 if (err < 0) {
2159 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002160 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002161 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002162
2163 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002164 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002165 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002166 if (!cache) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002167 int vif = ip6mr_find_vif(mrt, skb->dev);
2168
2169 if (vif >= 0)
2170 cache = ip6mr_cache_find_any(mrt,
2171 &ipv6_hdr(skb)->daddr,
2172 vif);
2173 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002174
2175 /*
2176 * No usable cache entry
2177 */
Ian Morris63159f22015-03-29 14:00:04 +01002178 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002179 int vif;
2180
Patrick McHardy6bd52142010-05-11 14:40:53 +02002181 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002182 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002183 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002184 read_unlock(&mrt_lock);
2185
2186 return err;
2187 }
2188 read_unlock(&mrt_lock);
2189 kfree_skb(skb);
2190 return -ENODEV;
2191 }
2192
Patrick McHardy6bd52142010-05-11 14:40:53 +02002193 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002194
2195 read_unlock(&mrt_lock);
2196
2197 return 0;
2198}
2199
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002200int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002201 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002202{
2203 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002204 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002205 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002206 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002207
Patrick McHardyd1db2752010-05-11 14:40:55 +02002208 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002209 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002210 return -ENOENT;
2211
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002212 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002213 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002214 if (!cache && skb->dev) {
2215 int vif = ip6mr_find_vif(mrt, skb->dev);
2216
2217 if (vif >= 0)
2218 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2219 vif);
2220 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002221
2222 if (!cache) {
2223 struct sk_buff *skb2;
2224 struct ipv6hdr *iph;
2225 struct net_device *dev;
2226 int vif;
2227
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002228 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002229 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002230 read_unlock(&mrt_lock);
2231 return -ENODEV;
2232 }
2233
2234 /* really correct? */
2235 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2236 if (!skb2) {
2237 read_unlock(&mrt_lock);
2238 return -ENOMEM;
2239 }
2240
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002241 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002242 skb_reset_transport_header(skb2);
2243
2244 skb_put(skb2, sizeof(struct ipv6hdr));
2245 skb_reset_network_header(skb2);
2246
2247 iph = ipv6_hdr(skb2);
2248 iph->version = 0;
2249 iph->priority = 0;
2250 iph->flow_lbl[0] = 0;
2251 iph->flow_lbl[1] = 0;
2252 iph->flow_lbl[2] = 0;
2253 iph->payload_len = 0;
2254 iph->nexthdr = IPPROTO_NONE;
2255 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002256 iph->saddr = rt->rt6i_src.addr;
2257 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002258
Patrick McHardy6bd52142010-05-11 14:40:53 +02002259 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002260 read_unlock(&mrt_lock);
2261
2262 return err;
2263 }
2264
Yuval Mintz7b0db852018-02-28 23:29:39 +02002265 err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002266 read_unlock(&mrt_lock);
2267 return err;
2268}
2269
Yuval Mintzb70432f2018-02-28 23:29:32 +02002270static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002271 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2272 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002273{
2274 struct nlmsghdr *nlh;
2275 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002276 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002277
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002278 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002279 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002280 return -EMSGSIZE;
2281
2282 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002283 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002284 rtm->rtm_dst_len = 128;
2285 rtm->rtm_src_len = 128;
2286 rtm->rtm_tos = 0;
2287 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002288 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2289 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002290 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002291 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002292 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002293 rtm->rtm_protocol = RTPROT_STATIC;
2294 else
2295 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002296 rtm->rtm_flags = 0;
2297
Jiri Benc930345e2015-03-29 16:59:25 +02002298 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2299 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002300 goto nla_put_failure;
Yuval Mintz7b0db852018-02-28 23:29:39 +02002301 err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002302 /* do not break the dump if cache is unresolved */
2303 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002304 goto nla_put_failure;
2305
Johannes Berg053c0952015-01-16 22:09:00 +01002306 nlmsg_end(skb, nlh);
2307 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002308
2309nla_put_failure:
2310 nlmsg_cancel(skb, nlh);
2311 return -EMSGSIZE;
2312}
2313
Yuval Mintz7b0db852018-02-28 23:29:39 +02002314static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
2315 u32 portid, u32 seq, struct mr_mfc *c,
2316 int cmd, int flags)
2317{
2318 return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c,
2319 cmd, flags);
2320}
2321
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002322static int mr6_msgsize(bool unresolved, int maxvif)
2323{
2324 size_t len =
2325 NLMSG_ALIGN(sizeof(struct rtmsg))
2326 + nla_total_size(4) /* RTA_TABLE */
2327 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2328 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2329 ;
2330
2331 if (!unresolved)
2332 len = len
2333 + nla_total_size(4) /* RTA_IIF */
2334 + nla_total_size(0) /* RTA_MULTIPATH */
2335 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2336 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002337 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002338 ;
2339
2340 return len;
2341}
2342
Yuval Mintzb70432f2018-02-28 23:29:32 +02002343static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002344 int cmd)
2345{
2346 struct net *net = read_pnet(&mrt->net);
2347 struct sk_buff *skb;
2348 int err = -ENOBUFS;
2349
Yuval Mintz494fff52018-02-28 23:29:34 +02002350 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002351 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002352 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002353 goto errout;
2354
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002355 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002356 if (err < 0)
2357 goto errout;
2358
2359 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2360 return;
2361
2362errout:
2363 kfree_skb(skb);
2364 if (err < 0)
2365 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2366}
2367
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002368static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2369{
2370 size_t len =
2371 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2372 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2373 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2374 /* IP6MRA_CREPORT_SRC_ADDR */
2375 + nla_total_size(sizeof(struct in6_addr))
2376 /* IP6MRA_CREPORT_DST_ADDR */
2377 + nla_total_size(sizeof(struct in6_addr))
2378 /* IP6MRA_CREPORT_PKT */
2379 + nla_total_size(payloadlen)
2380 ;
2381
2382 return len;
2383}
2384
Yuval Mintzb70432f2018-02-28 23:29:32 +02002385static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002386{
2387 struct net *net = read_pnet(&mrt->net);
2388 struct nlmsghdr *nlh;
2389 struct rtgenmsg *rtgenm;
2390 struct mrt6msg *msg;
2391 struct sk_buff *skb;
2392 struct nlattr *nla;
2393 int payloadlen;
2394
2395 payloadlen = pkt->len - sizeof(struct mrt6msg);
2396 msg = (struct mrt6msg *)skb_transport_header(pkt);
2397
2398 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2399 if (!skb)
2400 goto errout;
2401
2402 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2403 sizeof(struct rtgenmsg), 0);
2404 if (!nlh)
2405 goto errout;
2406 rtgenm = nlmsg_data(nlh);
2407 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2408 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2409 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2410 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2411 &msg->im6_src) ||
2412 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2413 &msg->im6_dst))
2414 goto nla_put_failure;
2415
2416 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2417 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2418 nla_data(nla), payloadlen))
2419 goto nla_put_failure;
2420
2421 nlmsg_end(skb, nlh);
2422
2423 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2424 return;
2425
2426nla_put_failure:
2427 nlmsg_cancel(skb, nlh);
2428errout:
2429 kfree_skb(skb);
2430 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2431}
2432
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002433static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2434{
Yuval Mintz7b0db852018-02-28 23:29:39 +02002435 return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
2436 _ip6mr_fill_mroute, &mfc_unres_lock);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002437}