blob: 4a15529d33eb2649eb09ea7cfd3b5fd0e8294329 [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,
183 struct fib_rule_hdr *frh, struct nlattr **tb)
184{
185 return 0;
186}
187
188static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
189 struct nlattr **tb)
190{
191 return 1;
192}
193
194static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
195 struct fib_rule_hdr *frh)
196{
197 frh->dst_len = 0;
198 frh->src_len = 0;
199 frh->tos = 0;
200 return 0;
201}
202
Andi Kleen04a6f822012-10-04 17:12:11 -0700203static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200204 .family = RTNL_FAMILY_IP6MR,
205 .rule_size = sizeof(struct ip6mr_rule),
206 .addr_size = sizeof(struct in6_addr),
207 .action = ip6mr_rule_action,
208 .match = ip6mr_rule_match,
209 .configure = ip6mr_rule_configure,
210 .compare = ip6mr_rule_compare,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200211 .fill = ip6mr_rule_fill,
212 .nlgroup = RTNLGRP_IPV6_RULE,
213 .policy = ip6mr_rule_policy,
214 .owner = THIS_MODULE,
215};
216
217static int __net_init ip6mr_rules_init(struct net *net)
218{
219 struct fib_rules_ops *ops;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200220 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200221 int err;
222
223 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
224 if (IS_ERR(ops))
225 return PTR_ERR(ops);
226
227 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
228
229 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100230 if (!mrt) {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200231 err = -ENOMEM;
232 goto err1;
233 }
234
235 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
236 if (err < 0)
237 goto err2;
238
239 net->ipv6.mr6_rules_ops = ops;
240 return 0;
241
242err2:
WANG Congf243e5a2015-03-25 14:45:03 -0700243 ip6mr_free_table(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200244err1:
245 fib_rules_unregister(ops);
246 return err;
247}
248
249static void __net_exit ip6mr_rules_exit(struct net *net)
250{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200251 struct mr_table *mrt, *next;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200252
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200253 rtnl_lock();
Eric Dumazet035320d2010-06-06 23:48:40 +0000254 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
255 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200256 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000257 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200258 fib_rules_unregister(net->ipv6.mr6_rules_ops);
WANG Cong419df122015-03-31 11:01:46 -0700259 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200260}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300261
262static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
263{
264 return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR);
265}
266
267static unsigned int ip6mr_rules_seq_read(struct net *net)
268{
269 return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
270}
Yuval Mintzd3c07e52018-03-26 15:01:35 +0300271
272bool ip6mr_rule_default(const struct fib_rule *rule)
273{
274 return fib_rule_matchall(rule) && rule->action == FR_ACT_TO_TBL &&
275 rule->table == RT6_TABLE_DFLT && !rule->l3mdev;
276}
277EXPORT_SYMBOL(ip6mr_rule_default);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200278#else
279#define ip6mr_for_each_table(mrt, net) \
280 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
281
Yuval Mintz7b0db852018-02-28 23:29:39 +0200282static struct mr_table *ip6mr_mr_table_iter(struct net *net,
283 struct mr_table *mrt)
284{
285 if (!mrt)
286 return net->ipv6.mrt6;
287 return NULL;
288}
289
Yuval Mintzb70432f2018-02-28 23:29:32 +0200290static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200291{
292 return net->ipv6.mrt6;
293}
294
David S. Miller4c9483b2011-03-12 16:22:43 -0500295static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200296 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200297{
298 *mrt = net->ipv6.mrt6;
299 return 0;
300}
301
302static int __net_init ip6mr_rules_init(struct net *net)
303{
304 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
305 return net->ipv6.mrt6 ? 0 : -ENOMEM;
306}
307
308static void __net_exit ip6mr_rules_exit(struct net *net)
309{
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200310 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200311 ip6mr_free_table(net->ipv6.mrt6);
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200312 net->ipv6.mrt6 = NULL;
313 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200314}
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300315
316static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb)
317{
318 return 0;
319}
320
321static unsigned int ip6mr_rules_seq_read(struct net *net)
322{
323 return 0;
324}
Patrick McHardyd1db2752010-05-11 14:40:55 +0200325#endif
326
Yuval Mintz87c418b2018-02-28 23:29:31 +0200327static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
328 const void *ptr)
329{
330 const struct mfc6_cache_cmp_arg *cmparg = arg->key;
331 struct mfc6_cache *c = (struct mfc6_cache *)ptr;
332
333 return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) ||
334 !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin);
335}
336
337static const struct rhashtable_params ip6mr_rht_params = {
Yuval Mintz494fff52018-02-28 23:29:34 +0200338 .head_offset = offsetof(struct mr_mfc, mnode),
Yuval Mintz87c418b2018-02-28 23:29:31 +0200339 .key_offset = offsetof(struct mfc6_cache, cmparg),
340 .key_len = sizeof(struct mfc6_cache_cmp_arg),
341 .nelem_hint = 3,
342 .locks_mul = 1,
343 .obj_cmpfn = ip6mr_hash_cmp,
344 .automatic_shrinking = true,
345};
346
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200347static void ip6mr_new_table_set(struct mr_table *mrt,
348 struct net *net)
349{
350#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
351 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
352#endif
353}
354
Yuval Mintz845c9a72018-02-28 23:29:35 +0200355static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = {
356 .mf6c_origin = IN6ADDR_ANY_INIT,
357 .mf6c_mcastgrp = IN6ADDR_ANY_INIT,
358};
359
360static struct mr_table_ops ip6mr_mr_table_ops = {
361 .rht_params = &ip6mr_rht_params,
362 .cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
363};
364
Yuval Mintzb70432f2018-02-28 23:29:32 +0200365static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200366{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200367 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200368
369 mrt = ip6mr_get_table(net, id);
Ian Morris53b24b82015-03-29 14:00:05 +0100370 if (mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200371 return mrt;
372
Yuval Mintz845c9a72018-02-28 23:29:35 +0200373 return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200374 ipmr_expire_process, ip6mr_new_table_set);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200375}
376
Yuval Mintzb70432f2018-02-28 23:29:32 +0200377static void ip6mr_free_table(struct mr_table *mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200378{
WANG Cong7ba0c472015-03-31 11:01:47 -0700379 del_timer_sync(&mrt->ipmr_expire_timer);
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +0100380 mroute_clean_tables(mrt, true);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200381 rhltable_destroy(&mrt->mfc_hash);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200382 kfree(mrt);
383}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900384
385#ifdef CONFIG_PROC_FS
Yuval Mintzc8d61962018-02-28 23:29:36 +0200386/* The /proc interfaces to multicast routing
387 * /proc/ip6_mr_cache /proc/ip6_mr_vif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900388 */
389
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900390static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
391 __acquires(mrt_lock)
392{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200393 struct mr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800394 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200395 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200396
397 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100398 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200399 return ERR_PTR(-ENOENT);
400
401 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800402
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900403 read_lock(&mrt_lock);
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200404 return mr_vif_seq_start(seq, pos);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900405}
406
407static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
408 __releases(mrt_lock)
409{
410 read_unlock(&mrt_lock);
411}
412
413static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
414{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200415 struct mr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200416 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800417
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900418 if (v == SEQ_START_TOKEN) {
419 seq_puts(seq,
420 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
421 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200422 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900423 const char *name = vif->dev ? vif->dev->name : "none";
424
425 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100426 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200427 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900428 name, vif->bytes_in, vif->pkt_in,
429 vif->bytes_out, vif->pkt_out,
430 vif->flags);
431 }
432 return 0;
433}
434
Stephen Hemminger98147d52009-09-01 19:25:02 +0000435static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900436 .start = ip6mr_vif_seq_start,
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200437 .next = mr_vif_seq_next,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900438 .stop = ip6mr_vif_seq_stop,
439 .show = ip6mr_vif_seq_show,
440};
441
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900442static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
443{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800444 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200445 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800446
Patrick McHardyd1db2752010-05-11 14:40:55 +0200447 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100448 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200449 return ERR_PTR(-ENOENT);
450
Yuval Mintzc8d61962018-02-28 23:29:36 +0200451 return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900452}
453
454static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
455{
456 int n;
457
458 if (v == SEQ_START_TOKEN) {
459 seq_puts(seq,
460 "Group "
461 "Origin "
462 "Iif Pkts Bytes Wrong Oifs\n");
463 } else {
464 const struct mfc6_cache *mfc = v;
Yuval Mintzc8d61962018-02-28 23:29:36 +0200465 const struct mr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200466 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900467
Benjamin Thery999890b2008-12-03 22:22:16 -0800468 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700469 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200470 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900471
Yuval Mintzb70432f2018-02-28 23:29:32 +0200472 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800473 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200474 mfc->_c.mfc_un.res.pkt,
475 mfc->_c.mfc_un.res.bytes,
476 mfc->_c.mfc_un.res.wrong_if);
477 for (n = mfc->_c.mfc_un.res.minvif;
478 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200479 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200480 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900481 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200482 " %2d:%-3d", n,
483 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900484 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800485 } else {
486 /* unresolved mfc_caches don't contain
487 * pkt, bytes and wrong_if values
488 */
489 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900490 }
491 seq_putc(seq, '\n');
492 }
493 return 0;
494}
495
James Morris88e9d342009-09-22 16:43:43 -0700496static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900497 .start = ipmr_mfc_seq_start,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200498 .next = mr_mfc_seq_next,
499 .stop = mr_mfc_seq_stop,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900500 .show = ipmr_mfc_seq_show,
501};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900502#endif
503
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900504#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900505
506static int pim6_rcv(struct sk_buff *skb)
507{
508 struct pimreghdr *pim;
509 struct ipv6hdr *encap;
510 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800511 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200512 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500513 struct flowi6 fl6 = {
514 .flowi6_iif = skb->dev->ifindex,
515 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200516 };
517 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900518
519 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
520 goto drop;
521
522 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100523 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900524 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800525 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
526 sizeof(*pim), IPPROTO_PIM,
527 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700528 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900529 goto drop;
530
531 /* check if the inner packet is destined to mcast group */
532 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
533 sizeof(*pim));
534
535 if (!ipv6_addr_is_multicast(&encap->daddr) ||
536 encap->payload_len == 0 ||
537 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
538 goto drop;
539
David S. Miller4c9483b2011-03-12 16:22:43 -0500540 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200541 goto drop;
542 reg_vif_num = mrt->mroute_reg_vif_num;
543
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900544 read_lock(&mrt_lock);
545 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200546 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900547 if (reg_dev)
548 dev_hold(reg_dev);
549 read_unlock(&mrt_lock);
550
Ian Morris63159f22015-03-29 14:00:04 +0100551 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900552 goto drop;
553
554 skb->mac_header = skb->network_header;
555 skb_pull(skb, (u8 *)encap - skb->data);
556 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800557 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000558 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700559
Nicolas Dichtelea231922013-09-02 15:34:58 +0200560 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700561
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000562 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000563
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900564 dev_put(reg_dev);
565 return 0;
566 drop:
567 kfree_skb(skb);
568 return 0;
569}
570
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000571static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900572 .handler = pim6_rcv,
573};
574
575/* Service routines creating virtual interfaces: PIMREG */
576
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000577static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
578 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900579{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800580 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200581 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500582 struct flowi6 fl6 = {
583 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700584 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500585 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200586 };
587 int err;
588
David S. Miller4c9483b2011-03-12 16:22:43 -0500589 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000590 if (err < 0) {
591 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200592 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000593 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800594
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900595 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700596 dev->stats.tx_bytes += skb->len;
597 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200598 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900599 read_unlock(&mrt_lock);
600 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000601 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900602}
603
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200604static int reg_vif_get_iflink(const struct net_device *dev)
605{
606 return 0;
607}
608
Stephen Hemminger007c3832008-11-20 20:28:35 -0800609static const struct net_device_ops reg_vif_netdev_ops = {
610 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200611 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800612};
613
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900614static void reg_vif_setup(struct net_device *dev)
615{
616 dev->type = ARPHRD_PIMREG;
617 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
618 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800619 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400620 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700621 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900622}
623
Yuval Mintzb70432f2018-02-28 23:29:32 +0200624static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900625{
626 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200627 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900628
Patrick McHardyd1db2752010-05-11 14:40:55 +0200629 if (mrt->id == RT6_TABLE_DFLT)
630 sprintf(name, "pim6reg");
631 else
632 sprintf(name, "pim6reg%u", mrt->id);
633
Tom Gundersenc835a672014-07-14 16:37:24 +0200634 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100635 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900636 return NULL;
637
Benjamin Thery8229efd2008-12-10 16:30:15 -0800638 dev_net_set(dev, net);
639
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900640 if (register_netdevice(dev)) {
641 free_netdev(dev);
642 return NULL;
643 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900644
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900645 if (dev_open(dev))
646 goto failure;
647
Wang Chen7af3db72008-07-14 20:54:54 -0700648 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900649 return dev;
650
651failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900652 unregister_netdevice(dev);
653 return NULL;
654}
655#endif
656
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300657static int call_ip6mr_vif_entry_notifiers(struct net *net,
658 enum fib_event_type event_type,
659 struct vif_device *vif,
660 mifi_t vif_index, u32 tb_id)
661{
662 return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
663 vif, vif_index, tb_id,
664 &net->ipv6.ipmr_seq);
665}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900666
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300667static int call_ip6mr_mfc_entry_notifiers(struct net *net,
668 enum fib_event_type event_type,
669 struct mfc6_cache *mfc, u32 tb_id)
670{
671 return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
672 &mfc->_c, tb_id, &net->ipv6.ipmr_seq);
673}
674
675/* Delete a VIF entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200676static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300677 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900678{
Yuval Mintz6853f212018-02-28 23:29:29 +0200679 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900680 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800681 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200682
683 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900684 return -EADDRNOTAVAIL;
685
Yuval Mintzb70432f2018-02-28 23:29:32 +0200686 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900687
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300688 if (VIF_EXISTS(mrt, vifi))
689 call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
690 FIB_EVENT_VIF_DEL, v, vifi,
691 mrt->id);
692
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900693 write_lock_bh(&mrt_lock);
694 dev = v->dev;
695 v->dev = NULL;
696
697 if (!dev) {
698 write_unlock_bh(&mrt_lock);
699 return -EADDRNOTAVAIL;
700 }
701
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900702#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200703 if (vifi == mrt->mroute_reg_vif_num)
704 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900705#endif
706
Patrick McHardy6bd52142010-05-11 14:40:53 +0200707 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900708 int tmp;
709 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200710 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900711 break;
712 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200713 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900714 }
715
716 write_unlock_bh(&mrt_lock);
717
718 dev_set_allmulti(dev, -1);
719
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800720 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000721 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800722 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700723 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000724 NETCONFA_MC_FORWARDING,
725 dev->ifindex, &in6_dev->cnf);
726 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800727
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300728 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000729 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900730
731 dev_put(dev);
732 return 0;
733}
734
Yuval Mintz87c418b2018-02-28 23:29:31 +0200735static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
736{
Yuval Mintz494fff52018-02-28 23:29:34 +0200737 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200738
Yuval Mintz494fff52018-02-28 23:29:34 +0200739 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200740}
741
Benjamin Thery58701ad2008-12-10 16:22:34 -0800742static inline void ip6mr_cache_free(struct mfc6_cache *c)
743{
Yuval Mintz494fff52018-02-28 23:29:34 +0200744 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800745}
746
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900747/* Destroy an unresolved cache entry, killing queued skbs
748 and reporting error to netlink readers.
749 */
750
Yuval Mintzb70432f2018-02-28 23:29:32 +0200751static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900752{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200753 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900754 struct sk_buff *skb;
755
Patrick McHardy6bd52142010-05-11 14:40:53 +0200756 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900757
Yuval Mintz494fff52018-02-28 23:29:34 +0200758 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900759 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200760 struct nlmsghdr *nlh = skb_pull(skb,
761 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900762 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000763 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900764 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000765 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000766 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900767 } else
768 kfree_skb(skb);
769 }
770
Benjamin Thery58701ad2008-12-10 16:22:34 -0800771 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900772}
773
774
Patrick McHardyc476efb2010-05-11 14:40:48 +0200775/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900776
Yuval Mintzb70432f2018-02-28 23:29:32 +0200777static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900778{
779 unsigned long now = jiffies;
780 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200781 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900782
Yuval Mintzb70432f2018-02-28 23:29:32 +0200783 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900784 if (time_after(c->mfc_un.unres.expires, now)) {
785 /* not yet... */
786 unsigned long interval = c->mfc_un.unres.expires - now;
787 if (interval < expires)
788 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900789 continue;
790 }
791
Patrick McHardyf30a77842010-05-11 14:40:51 +0200792 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200793 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
794 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900795 }
796
Yuval Mintzb70432f2018-02-28 23:29:32 +0200797 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200798 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900799}
800
Kees Cooke99e88a2017-10-16 14:43:17 -0700801static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900802{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200803 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200804
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900805 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200806 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900807 return;
808 }
809
Yuval Mintzb70432f2018-02-28 23:29:32 +0200810 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200811 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900812
813 spin_unlock(&mfc_unres_lock);
814}
815
816/* Fill oifs list. It is called under write locked mrt_lock. */
817
Yuval Mintzb70432f2018-02-28 23:29:32 +0200818static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200819 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200820 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900821{
822 int vifi;
823
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300824 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900825 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300826 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900827
Patrick McHardy6bd52142010-05-11 14:40:53 +0200828 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200829 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800830 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900831 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
832 if (cache->mfc_un.res.minvif > vifi)
833 cache->mfc_un.res.minvif = vifi;
834 if (cache->mfc_un.res.maxvif <= vifi)
835 cache->mfc_un.res.maxvif = vifi + 1;
836 }
837 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200838 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900839}
840
Yuval Mintzb70432f2018-02-28 23:29:32 +0200841static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200842 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900843{
844 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200845 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900846 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800847 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700848 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900849
850 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200851 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900852 return -EADDRINUSE;
853
854 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900855#ifdef CONFIG_IPV6_PIMSM_V2
856 case MIFF_REGISTER:
857 /*
858 * Special Purpose VIF in PIM
859 * All the packets will be sent to the daemon
860 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200861 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900862 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200863 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900864 if (!dev)
865 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700866 err = dev_set_allmulti(dev, 1);
867 if (err) {
868 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700869 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700870 return err;
871 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900872 break;
873#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900874 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800875 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900876 if (!dev)
877 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700878 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700879 if (err) {
880 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700881 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700882 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900883 break;
884 default:
885 return -EINVAL;
886 }
887
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800888 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000889 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800890 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700891 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000892 NETCONFA_MC_FORWARDING,
893 dev->ifindex, &in6_dev->cnf);
894 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800895
Yuval Mintz6853f212018-02-28 23:29:29 +0200896 /* Fill in the VIF structures */
897 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
898 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
899 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900900
901 /* And finish update writing critical data */
902 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900903 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900904#ifdef CONFIG_IPV6_PIMSM_V2
905 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200906 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900907#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200908 if (vifi + 1 > mrt->maxvif)
909 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900910 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +0300911 call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
912 v, vifi, mrt->id);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900913 return 0;
914}
915
Yuval Mintzb70432f2018-02-28 23:29:32 +0200916static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000917 const struct in6_addr *origin,
918 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900919{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200920 struct mfc6_cache_cmp_arg arg = {
921 .mf6c_origin = *origin,
922 .mf6c_mcastgrp = *mcastgrp,
923 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900924
Yuval Mintz845c9a72018-02-28 23:29:35 +0200925 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000926}
927
928/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200929static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000930 struct in6_addr *mcastgrp,
931 mifi_t mifi)
932{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200933 struct mfc6_cache_cmp_arg arg = {
934 .mf6c_origin = in6addr_any,
935 .mf6c_mcastgrp = *mcastgrp,
936 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000937
938 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +0200939 return mr_mfc_find_any_parent(mrt, mifi);
940 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000941}
942
Yuval Mintz87c418b2018-02-28 23:29:31 +0200943/* Look for a (S,G,iif) entry if parent != -1 */
944static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +0200945ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +0200946 const struct in6_addr *origin,
947 const struct in6_addr *mcastgrp,
948 int parent)
949{
950 struct mfc6_cache_cmp_arg arg = {
951 .mf6c_origin = *origin,
952 .mf6c_mcastgrp = *mcastgrp,
953 };
Yuval Mintz87c418b2018-02-28 23:29:31 +0200954
Yuval Mintz845c9a72018-02-28 23:29:35 +0200955 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200956}
957
Yuval Mintz845c9a72018-02-28 23:29:35 +0200958/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200959static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900960{
Joe Perches36cbac52008-12-03 22:27:25 -0800961 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100962 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900963 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200964 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
965 c->_c.mfc_un.res.minvif = MAXMIFS;
Yuval Mintz8c13af22018-03-26 15:01:36 +0300966 c->_c.free = ip6mr_cache_free_rcu;
967 refcount_set(&c->_c.mfc_un.res.refcount, 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900968 return c;
969}
970
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200971static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900972{
Joe Perches36cbac52008-12-03 22:27:25 -0800973 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +0100974 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900975 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200976 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
977 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900978 return c;
979}
980
981/*
982 * A cache entry has gone into a resolved state from queued
983 */
984
Yuval Mintzb70432f2018-02-28 23:29:32 +0200985static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200986 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900987{
988 struct sk_buff *skb;
989
990 /*
991 * Play the pending entries through our router
992 */
993
Yuval Mintz494fff52018-02-28 23:29:34 +0200994 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900995 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200996 struct nlmsghdr *nlh = skb_pull(skb,
997 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900998
Yuval Mintz7b0db852018-02-28 23:29:39 +0200999 if (mr_fill_mroute(mrt, skb, &c->_c,
1000 nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001001 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001002 } else {
1003 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +00001004 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001005 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +00001006 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001007 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001008 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001009 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001010 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001011 }
1012}
1013
1014/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001015 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001016 *
1017 * Called under mrt_lock.
1018 */
1019
Yuval Mintzb70432f2018-02-28 23:29:32 +02001020static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001021 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001022{
Yuval Mintz8571ab42018-02-28 23:29:30 +02001023 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001024 struct sk_buff *skb;
1025 struct mrt6msg *msg;
1026 int ret;
1027
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001028#ifdef CONFIG_IPV6_PIMSM_V2
1029 if (assert == MRT6MSG_WHOLEPKT)
1030 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1031 +sizeof(*msg));
1032 else
1033#endif
1034 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001035
1036 if (!skb)
1037 return -ENOBUFS;
1038
1039 /* I suppose that internal messages
1040 * do not require checksums */
1041
1042 skb->ip_summed = CHECKSUM_UNNECESSARY;
1043
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001044#ifdef CONFIG_IPV6_PIMSM_V2
1045 if (assert == MRT6MSG_WHOLEPKT) {
1046 /* Ugly, but we have no choice with this interface.
1047 Duplicate old header, fix length etc.
1048 And all this only to mangle msg->im6_msgtype and
1049 to set msg->im6_mbz to "mbz" :-)
1050 */
1051 skb_push(skb, -skb_network_offset(pkt));
1052
1053 skb_push(skb, sizeof(*msg));
1054 skb_reset_transport_header(skb);
1055 msg = (struct mrt6msg *)skb_transport_header(skb);
1056 msg->im6_mbz = 0;
1057 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001058 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001059 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001060 msg->im6_src = ipv6_hdr(pkt)->saddr;
1061 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001062
1063 skb->ip_summed = CHECKSUM_UNNECESSARY;
1064 } else
1065#endif
1066 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001067 /*
1068 * Copy the IP header
1069 */
1070
1071 skb_put(skb, sizeof(struct ipv6hdr));
1072 skb_reset_network_header(skb);
1073 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1074
1075 /*
1076 * Add our header
1077 */
1078 skb_put(skb, sizeof(*msg));
1079 skb_reset_transport_header(skb);
1080 msg = (struct mrt6msg *)skb_transport_header(skb);
1081
1082 msg->im6_mbz = 0;
1083 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001084 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001085 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001086 msg->im6_src = ipv6_hdr(pkt)->saddr;
1087 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001088
Eric Dumazetadf30902009-06-02 05:19:30 +00001089 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001090 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001091 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001092
Yuval Mintz8571ab42018-02-28 23:29:30 +02001093 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001094 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001095 if (!mroute6_sk) {
1096 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001097 kfree_skb(skb);
1098 return -EINVAL;
1099 }
1100
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001101 mrt6msg_netlink_event(mrt, skb);
1102
Yuval Mintz8571ab42018-02-28 23:29:30 +02001103 /* Deliver to user space multicast routing algorithms */
1104 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1105 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001106 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001107 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001108 kfree_skb(skb);
1109 }
1110
1111 return ret;
1112}
1113
Yuval Mintz494fff52018-02-28 23:29:34 +02001114/* Queue a packet for resolution. It gets locked cache entry! */
1115static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
1116 struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001117{
Yuval Mintz494fff52018-02-28 23:29:34 +02001118 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001119 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001120 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001121
1122 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001123 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001124 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001125 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1126 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001127 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001128 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001129 }
1130
Patrick McHardyf30a77842010-05-11 14:40:51 +02001131 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001132 /*
1133 * Create a new entry if allowable
1134 */
1135
Patrick McHardy6bd52142010-05-11 14:40:53 +02001136 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001137 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001138 spin_unlock_bh(&mfc_unres_lock);
1139
1140 kfree_skb(skb);
1141 return -ENOBUFS;
1142 }
1143
Yuval Mintz494fff52018-02-28 23:29:34 +02001144 /* Fill in the new cache entry */
1145 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001146 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1147 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1148
1149 /*
1150 * Reflect first query at pim6sd
1151 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001152 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001153 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001154 /* If the report failed throw the cache entry
1155 out - Brad Parker
1156 */
1157 spin_unlock_bh(&mfc_unres_lock);
1158
Benjamin Thery58701ad2008-12-10 16:22:34 -08001159 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001160 kfree_skb(skb);
1161 return err;
1162 }
1163
Patrick McHardy6bd52142010-05-11 14:40:53 +02001164 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001165 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001166 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001167
Patrick McHardy6bd52142010-05-11 14:40:53 +02001168 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001169 }
1170
Yuval Mintz494fff52018-02-28 23:29:34 +02001171 /* See if we can append the packet */
1172 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001173 kfree_skb(skb);
1174 err = -ENOBUFS;
1175 } else {
Yuval Mintz494fff52018-02-28 23:29:34 +02001176 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001177 err = 0;
1178 }
1179
1180 spin_unlock_bh(&mfc_unres_lock);
1181 return err;
1182}
1183
1184/*
1185 * MFC6 cache manipulation by user space
1186 */
1187
Yuval Mintzb70432f2018-02-28 23:29:32 +02001188static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001189 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001190{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001191 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001192
Yuval Mintz87c418b2018-02-28 23:29:31 +02001193 /* The entries are added/deleted only under RTNL */
1194 rcu_read_lock();
1195 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1196 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1197 rcu_read_unlock();
1198 if (!c)
1199 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001200 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1201 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001202
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001203 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1204 FIB_EVENT_ENTRY_DEL, c, mrt->id);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001205 mr6_netlink_event(mrt, c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001206 mr_cache_put(&c->_c);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001207 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001208}
1209
1210static int ip6mr_device_event(struct notifier_block *this,
1211 unsigned long event, void *ptr)
1212{
Jiri Pirko351638e2013-05-28 01:30:21 +00001213 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001214 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001215 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001216 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001217 int ct;
1218
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001219 if (event != NETDEV_UNREGISTER)
1220 return NOTIFY_DONE;
1221
Patrick McHardyd1db2752010-05-11 14:40:55 +02001222 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001223 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001224 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1225 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001226 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001227 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001228 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001229
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001230 return NOTIFY_DONE;
1231}
1232
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001233static unsigned int ip6mr_seq_read(struct net *net)
1234{
1235 ASSERT_RTNL();
1236
1237 return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
1238}
1239
1240static int ip6mr_dump(struct net *net, struct notifier_block *nb)
1241{
1242 return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
1243 ip6mr_mr_table_iter, &mrt_lock);
1244}
1245
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001246static struct notifier_block ip6_mr_notifier = {
1247 .notifier_call = ip6mr_device_event
1248};
1249
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001250static const struct fib_notifier_ops ip6mr_notifier_ops_template = {
1251 .family = RTNL_FAMILY_IP6MR,
1252 .fib_seq_read = ip6mr_seq_read,
1253 .fib_dump = ip6mr_dump,
1254 .owner = THIS_MODULE,
1255};
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001256
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001257static int __net_init ip6mr_notifier_init(struct net *net)
1258{
1259 struct fib_notifier_ops *ops;
1260
1261 net->ipv6.ipmr_seq = 0;
1262
1263 ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
1264 if (IS_ERR(ops))
1265 return PTR_ERR(ops);
1266
1267 net->ipv6.ip6mr_notifier_ops = ops;
1268
1269 return 0;
1270}
1271
1272static void __net_exit ip6mr_notifier_exit(struct net *net)
1273{
1274 fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops);
1275 net->ipv6.ip6mr_notifier_ops = NULL;
1276}
1277
1278/* Setup for IP multicast routing */
Benjamin Thery4e168802008-12-10 16:15:08 -08001279static int __net_init ip6mr_net_init(struct net *net)
1280{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001281 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001282
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001283 err = ip6mr_notifier_init(net);
1284 if (err)
1285 return err;
1286
Patrick McHardyd1db2752010-05-11 14:40:55 +02001287 err = ip6mr_rules_init(net);
1288 if (err < 0)
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001289 goto ip6mr_rules_fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001290
1291#ifdef CONFIG_PROC_FS
1292 err = -ENOMEM;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001293 if (!proc_create_net("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_seq_ops,
1294 sizeof(struct mr_vif_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001295 goto proc_vif_fail;
Christoph Hellwigc3506372018-04-10 19:42:55 +02001296 if (!proc_create_net("ip6_mr_cache", 0, net->proc_net, &ipmr_mfc_seq_ops,
1297 sizeof(struct mr_mfc_iter)))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001298 goto proc_cache_fail;
1299#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001300
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001301 return 0;
1302
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001303#ifdef CONFIG_PROC_FS
1304proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001305 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001306proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001307 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001308#endif
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001309ip6mr_rules_fail:
1310 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001311 return err;
1312}
1313
1314static void __net_exit ip6mr_net_exit(struct net *net)
1315{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001316#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001317 remove_proc_entry("ip6_mr_cache", net->proc_net);
1318 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001319#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001320 ip6mr_rules_exit(net);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001321 ip6mr_notifier_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001322}
1323
1324static struct pernet_operations ip6mr_net_ops = {
1325 .init = ip6mr_net_init,
1326 .exit = ip6mr_net_exit,
1327};
1328
Wang Chen623d1a12008-07-03 12:13:30 +08001329int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001330{
Wang Chen623d1a12008-07-03 12:13:30 +08001331 int err;
1332
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001333 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1334 sizeof(struct mfc6_cache),
1335 0, SLAB_HWCACHE_ALIGN,
1336 NULL);
1337 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001338 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001339
Benjamin Thery4e168802008-12-10 16:15:08 -08001340 err = register_pernet_subsys(&ip6mr_net_ops);
1341 if (err)
1342 goto reg_pernet_fail;
1343
Wang Chen623d1a12008-07-03 12:13:30 +08001344 err = register_netdevice_notifier(&ip6_mr_notifier);
1345 if (err)
1346 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001347#ifdef CONFIG_IPV6_PIMSM_V2
1348 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001349 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001350 err = -EAGAIN;
1351 goto add_proto_fail;
1352 }
1353#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001354 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1355 NULL, ip6mr_rtm_dumproute, 0);
1356 if (err == 0)
1357 return 0;
1358
Tom Goff403dbb92009-06-14 03:16:13 -07001359#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001360 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001361add_proto_fail:
1362 unregister_netdevice_notifier(&ip6_mr_notifier);
1363#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001364reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001365 unregister_pernet_subsys(&ip6mr_net_ops);
1366reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001367 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001368 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001369}
1370
Wang Chen623d1a12008-07-03 12:13:30 +08001371void ip6_mr_cleanup(void)
1372{
Duan Jiongffb13882014-11-19 09:35:39 +08001373 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1374#ifdef CONFIG_IPV6_PIMSM_V2
1375 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1376#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001377 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001378 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001379 kmem_cache_destroy(mrt_cachep);
1380}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001381
Yuval Mintzb70432f2018-02-28 23:29:32 +02001382static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001383 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001384{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001385 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001386 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001387 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001388 bool found;
1389 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001390
Patrick McHardya50436f22010-03-17 06:04:14 +00001391 if (mfc->mf6cc_parent >= MAXMIFS)
1392 return -ENFILE;
1393
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001394 memset(ttls, 255, MAXMIFS);
1395 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001396 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1397 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001398 }
1399
Yuval Mintz87c418b2018-02-28 23:29:31 +02001400 /* The entries are added/deleted only under RTNL */
1401 rcu_read_lock();
1402 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1403 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1404 rcu_read_unlock();
1405 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001406 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001407 c->_c.mfc_parent = mfc->mf6cc_parent;
1408 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001409 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001410 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001411 write_unlock_bh(&mrt_lock);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001412 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
1413 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001414 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001415 return 0;
1416 }
1417
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001418 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1419 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001420 return -EINVAL;
1421
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001422 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001423 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001424 return -ENOMEM;
1425
1426 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1427 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001428 c->_c.mfc_parent = mfc->mf6cc_parent;
1429 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001430 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001431 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001432
Yuval Mintz494fff52018-02-28 23:29:34 +02001433 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001434 ip6mr_rht_params);
1435 if (err) {
1436 pr_err("ip6mr: rhtable insert error %d\n", err);
1437 ip6mr_cache_free(c);
1438 return err;
1439 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001440 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001441
Yuval Mintz87c418b2018-02-28 23:29:31 +02001442 /* Check to see if we resolved a queued list. If so we
1443 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001444 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001445 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001446 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001447 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1448 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001449 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001450 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001451 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001452 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001453 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001454 break;
1455 }
1456 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001457 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001458 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001459 spin_unlock_bh(&mfc_unres_lock);
1460
Patrick McHardyf30a77842010-05-11 14:40:51 +02001461 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001462 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001463 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001464 }
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001465 call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
1466 c, mrt->id);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001467 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001468 return 0;
1469}
1470
1471/*
1472 * Close the multicast socket, and clear the vif tables etc
1473 */
1474
Yuval Mintzb70432f2018-02-28 23:29:32 +02001475static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001476{
Yuval Mintz494fff52018-02-28 23:29:34 +02001477 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001478 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001479 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001480
Yuval Mintz87c418b2018-02-28 23:29:31 +02001481 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001482 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001483 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001484 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001485 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001486 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001487 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001488
Yuval Mintz87c418b2018-02-28 23:29:31 +02001489 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001490 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001491 if (!all && (c->mfc_flags & MFC_STATIC))
1492 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001493 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001494 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001495 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
Yuval Mintz8c13af22018-03-26 15:01:36 +03001496 mr_cache_put(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001497 }
1498
Patrick McHardy6bd52142010-05-11 14:40:53 +02001499 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001500 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001501 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001502 list_del(&c->list);
Yuval Mintz088aa3e2018-03-26 15:01:34 +03001503 call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
1504 FIB_EVENT_ENTRY_DEL,
1505 (struct mfc6_cache *)c,
1506 mrt->id);
Yuval Mintz494fff52018-02-28 23:29:34 +02001507 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1508 RTM_DELROUTE);
1509 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001510 }
1511 spin_unlock_bh(&mfc_unres_lock);
1512 }
1513}
1514
Yuval Mintzb70432f2018-02-28 23:29:32 +02001515static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001516{
1517 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001518 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001519
1520 rtnl_lock();
1521 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001522 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001523 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001524 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001525 rcu_assign_pointer(mrt->mroute_sk, sk);
Eric Dumazeta366e302018-03-07 08:43:19 -08001526 sock_set_flag(sk, SOCK_RCU_FREE);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001527 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001528 }
1529 write_unlock_bh(&mrt_lock);
1530
1531 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001532 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1533 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001534 NETCONFA_IFINDEX_ALL,
1535 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001536 rtnl_unlock();
1537
1538 return err;
1539}
1540
1541int ip6mr_sk_done(struct sock *sk)
1542{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001543 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001544 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001545 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001546
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001547 if (sk->sk_type != SOCK_RAW ||
1548 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1549 return err;
1550
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001551 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001552 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001553 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001554 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001555 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Eric Dumazeta366e302018-03-07 08:43:19 -08001556 /* Note that mroute_sk had SOCK_RCU_FREE set,
1557 * so the RCU grace period before sk freeing
1558 * is guaranteed by sk_destruct()
1559 */
Patrick McHardyd1db2752010-05-11 14:40:55 +02001560 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001561 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001562 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001563 NETCONFA_MC_FORWARDING,
1564 NETCONFA_IFINDEX_ALL,
1565 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001566
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001567 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001568 err = 0;
1569 break;
1570 }
1571 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001572 rtnl_unlock();
1573
1574 return err;
1575}
1576
Yuval Mintz8571ab42018-02-28 23:29:30 +02001577bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001578{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001579 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001580 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001581 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001582 .flowi6_oif = skb->dev->ifindex,
1583 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001584 };
1585
David S. Miller4c9483b2011-03-12 16:22:43 -05001586 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001587 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001588
Yuval Mintzb70432f2018-02-28 23:29:32 +02001589 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001590}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001591EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001592
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001593/*
1594 * Socket options and virtual interface manipulation. The whole
1595 * virtual interface system is a complete heap, but unfortunately
1596 * that's how BSD mrouted happens to think. Maybe one day with a proper
1597 * MOSPF/PIM router set up we can clean this up.
1598 */
1599
David S. Millerb7058842009-09-30 16:12:20 -07001600int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001601{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001602 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001603 struct mif6ctl vif;
1604 struct mf6cctl mfc;
1605 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001606 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001607 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001608
Xin Long99253eb2017-02-24 16:29:06 +08001609 if (sk->sk_type != SOCK_RAW ||
1610 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1611 return -EOPNOTSUPP;
1612
Patrick McHardyd1db2752010-05-11 14:40:55 +02001613 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001614 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001615 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001616
1617 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001618 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001619 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001620 return -EACCES;
1621 }
1622
1623 switch (optname) {
1624 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001625 if (optlen < sizeof(int))
1626 return -EINVAL;
1627
Patrick McHardy6bd52142010-05-11 14:40:53 +02001628 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001629
1630 case MRT6_DONE:
1631 return ip6mr_sk_done(sk);
1632
1633 case MRT6_ADD_MIF:
1634 if (optlen < sizeof(vif))
1635 return -EINVAL;
1636 if (copy_from_user(&vif, optval, sizeof(vif)))
1637 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001638 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001639 return -ENFILE;
1640 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001641 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001642 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001643 rtnl_unlock();
1644 return ret;
1645
1646 case MRT6_DEL_MIF:
1647 if (optlen < sizeof(mifi_t))
1648 return -EINVAL;
1649 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1650 return -EFAULT;
1651 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001652 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001653 rtnl_unlock();
1654 return ret;
1655
1656 /*
1657 * Manipulate the forwarding caches. These live
1658 * in a sort of kernel/user symbiosis.
1659 */
1660 case MRT6_ADD_MFC:
1661 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001662 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001663 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001664 case MRT6_ADD_MFC_PROXY:
1665 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001666 if (optlen < sizeof(mfc))
1667 return -EINVAL;
1668 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1669 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001670 if (parent == 0)
1671 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001672 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001673 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1674 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001675 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001676 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001677 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001678 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001679 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001680 rtnl_unlock();
1681 return ret;
1682
1683 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001684 * Control PIM assert (to activate pim will activate assert)
1685 */
1686 case MRT6_ASSERT:
1687 {
1688 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001689
1690 if (optlen != sizeof(v))
1691 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001692 if (get_user(v, (int __user *)optval))
1693 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001694 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001695 return 0;
1696 }
1697
1698#ifdef CONFIG_IPV6_PIMSM_V2
1699 case MRT6_PIM:
1700 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001701 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001702
1703 if (optlen != sizeof(v))
1704 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001705 if (get_user(v, (int __user *)optval))
1706 return -EFAULT;
1707 v = !!v;
1708 rtnl_lock();
1709 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001710 if (v != mrt->mroute_do_pim) {
1711 mrt->mroute_do_pim = v;
1712 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001713 }
1714 rtnl_unlock();
1715 return ret;
1716 }
1717
1718#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001719#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1720 case MRT6_TABLE:
1721 {
1722 u32 v;
1723
1724 if (optlen != sizeof(u32))
1725 return -EINVAL;
1726 if (get_user(v, (u32 __user *)optval))
1727 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001728 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1729 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1730 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001731 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001732 return -EBUSY;
1733
1734 rtnl_lock();
1735 ret = 0;
1736 if (!ip6mr_new_table(net, v))
1737 ret = -ENOMEM;
1738 raw6_sk(sk)->ip6mr_table = v;
1739 rtnl_unlock();
1740 return ret;
1741 }
1742#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001743 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001744 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001745 * set.
1746 */
1747 default:
1748 return -ENOPROTOOPT;
1749 }
1750}
1751
1752/*
1753 * Getsock opt support for the multicast routing system.
1754 */
1755
1756int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1757 int __user *optlen)
1758{
1759 int olr;
1760 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001761 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001762 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001763
Xin Long99253eb2017-02-24 16:29:06 +08001764 if (sk->sk_type != SOCK_RAW ||
1765 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1766 return -EOPNOTSUPP;
1767
Patrick McHardyd1db2752010-05-11 14:40:55 +02001768 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001769 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001770 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001771
1772 switch (optname) {
1773 case MRT6_VERSION:
1774 val = 0x0305;
1775 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001776#ifdef CONFIG_IPV6_PIMSM_V2
1777 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001778 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001779 break;
1780#endif
1781 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001782 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001783 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001784 default:
1785 return -ENOPROTOOPT;
1786 }
1787
1788 if (get_user(olr, optlen))
1789 return -EFAULT;
1790
1791 olr = min_t(int, olr, sizeof(int));
1792 if (olr < 0)
1793 return -EINVAL;
1794
1795 if (put_user(olr, optlen))
1796 return -EFAULT;
1797 if (copy_to_user(optval, &val, olr))
1798 return -EFAULT;
1799 return 0;
1800}
1801
1802/*
1803 * The IP multicast ioctl support routines.
1804 */
1805
1806int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1807{
1808 struct sioc_sg_req6 sr;
1809 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001810 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001811 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001812 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001813 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001814
1815 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001816 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001817 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001818
1819 switch (cmd) {
1820 case SIOCGETMIFCNT_IN6:
1821 if (copy_from_user(&vr, arg, sizeof(vr)))
1822 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001823 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001824 return -EINVAL;
1825 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001826 vif = &mrt->vif_table[vr.mifi];
1827 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001828 vr.icount = vif->pkt_in;
1829 vr.ocount = vif->pkt_out;
1830 vr.ibytes = vif->bytes_in;
1831 vr.obytes = vif->bytes_out;
1832 read_unlock(&mrt_lock);
1833
1834 if (copy_to_user(arg, &vr, sizeof(vr)))
1835 return -EFAULT;
1836 return 0;
1837 }
1838 read_unlock(&mrt_lock);
1839 return -EADDRNOTAVAIL;
1840 case SIOCGETSGCNT_IN6:
1841 if (copy_from_user(&sr, arg, sizeof(sr)))
1842 return -EFAULT;
1843
Yuval Mintz87c418b2018-02-28 23:29:31 +02001844 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001845 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001846 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001847 sr.pktcnt = c->_c.mfc_un.res.pkt;
1848 sr.bytecnt = c->_c.mfc_un.res.bytes;
1849 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001850 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001851
1852 if (copy_to_user(arg, &sr, sizeof(sr)))
1853 return -EFAULT;
1854 return 0;
1855 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001856 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001857 return -EADDRNOTAVAIL;
1858 default:
1859 return -ENOIOCTLCMD;
1860 }
1861}
1862
David S. Millere2d57762011-02-03 17:59:32 -08001863#ifdef CONFIG_COMPAT
1864struct compat_sioc_sg_req6 {
1865 struct sockaddr_in6 src;
1866 struct sockaddr_in6 grp;
1867 compat_ulong_t pktcnt;
1868 compat_ulong_t bytecnt;
1869 compat_ulong_t wrong_if;
1870};
1871
1872struct compat_sioc_mif_req6 {
1873 mifi_t mifi;
1874 compat_ulong_t icount;
1875 compat_ulong_t ocount;
1876 compat_ulong_t ibytes;
1877 compat_ulong_t obytes;
1878};
1879
1880int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1881{
1882 struct compat_sioc_sg_req6 sr;
1883 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001884 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001885 struct mfc6_cache *c;
1886 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001887 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001888
1889 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001890 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001891 return -ENOENT;
1892
1893 switch (cmd) {
1894 case SIOCGETMIFCNT_IN6:
1895 if (copy_from_user(&vr, arg, sizeof(vr)))
1896 return -EFAULT;
1897 if (vr.mifi >= mrt->maxvif)
1898 return -EINVAL;
1899 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001900 vif = &mrt->vif_table[vr.mifi];
1901 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001902 vr.icount = vif->pkt_in;
1903 vr.ocount = vif->pkt_out;
1904 vr.ibytes = vif->bytes_in;
1905 vr.obytes = vif->bytes_out;
1906 read_unlock(&mrt_lock);
1907
1908 if (copy_to_user(arg, &vr, sizeof(vr)))
1909 return -EFAULT;
1910 return 0;
1911 }
1912 read_unlock(&mrt_lock);
1913 return -EADDRNOTAVAIL;
1914 case SIOCGETSGCNT_IN6:
1915 if (copy_from_user(&sr, arg, sizeof(sr)))
1916 return -EFAULT;
1917
Yuval Mintz87c418b2018-02-28 23:29:31 +02001918 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001919 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1920 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001921 sr.pktcnt = c->_c.mfc_un.res.pkt;
1922 sr.bytecnt = c->_c.mfc_un.res.bytes;
1923 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001924 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001925
1926 if (copy_to_user(arg, &sr, sizeof(sr)))
1927 return -EFAULT;
1928 return 0;
1929 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001930 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001931 return -EADDRNOTAVAIL;
1932 default:
1933 return -ENOIOCTLCMD;
1934 }
1935}
1936#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001937
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001938static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001939{
Eric Dumazet1d015502016-04-27 16:44:40 -07001940 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1941 IPSTATS_MIB_OUTFORWDATAGRAMS);
1942 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1943 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001944 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001945}
1946
1947/*
1948 * Processing handlers for ip6mr_forward
1949 */
1950
Yuval Mintzb70432f2018-02-28 23:29:32 +02001951static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001952 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001953{
1954 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001955 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001956 struct net_device *dev;
1957 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001958 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001959
Ian Morris63159f22015-03-29 14:00:04 +01001960 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001961 goto out_free;
1962
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001963#ifdef CONFIG_IPV6_PIMSM_V2
1964 if (vif->flags & MIFF_REGISTER) {
1965 vif->pkt_out++;
1966 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001967 vif->dev->stats.tx_bytes += skb->len;
1968 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001969 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001970 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001971 }
1972#endif
1973
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001974 ipv6h = ipv6_hdr(skb);
1975
David S. Miller4c9483b2011-03-12 16:22:43 -05001976 fl6 = (struct flowi6) {
1977 .flowi6_oif = vif->link,
1978 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001979 };
1980
David S. Miller4c9483b2011-03-12 16:22:43 -05001981 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001982 if (dst->error) {
1983 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001984 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00001985 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001986
Eric Dumazetadf30902009-06-02 05:19:30 +00001987 skb_dst_drop(skb);
1988 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001989
1990 /*
1991 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1992 * not only before forwarding, but after forwarding on all output
1993 * interfaces. It is clear, if mrouter runs a multicasting
1994 * program, it should receive packets not depending to what interface
1995 * program is joined.
1996 * If we will not make it, the program will have to join on all
1997 * interfaces. On the other hand, multihoming host (or router, but
1998 * not mrouter) cannot join to more than one interface - it will
1999 * result in receiving multiple packets.
2000 */
2001 dev = vif->dev;
2002 skb->dev = dev;
2003 vif->pkt_out++;
2004 vif->bytes_out += skb->len;
2005
2006 /* We are about to write */
2007 /* XXX: extension headers? */
2008 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2009 goto out_free;
2010
2011 ipv6h = ipv6_hdr(skb);
2012 ipv6h->hop_limit--;
2013
2014 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2015
Eric W. Biederman29a26a52015-09-15 20:04:16 -05002016 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
2017 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002018 ip6mr_forward2_finish);
2019
2020out_free:
2021 kfree_skb(skb);
2022 return 0;
2023}
2024
Yuval Mintzb70432f2018-02-28 23:29:32 +02002025static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002026{
2027 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002028
2029 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02002030 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002031 break;
2032 }
2033 return ct;
2034}
2035
Yuval Mintzb70432f2018-02-28 23:29:32 +02002036static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +02002037 struct sk_buff *skb, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002038{
2039 int psend = -1;
2040 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002041 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002042
Yuval Mintz494fff52018-02-28 23:29:34 +02002043 vif = c->_c.mfc_parent;
2044 c->_c.mfc_un.res.pkt++;
2045 c->_c.mfc_un.res.bytes += skb->len;
2046 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002047
Yuval Mintz494fff52018-02-28 23:29:34 +02002048 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002049 struct mfc6_cache *cache_proxy;
2050
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01002051 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002052 * interface is part of the static tree.
2053 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02002054 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02002055 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002056 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002057 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002058 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002059 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02002060 }
2061 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002062 }
2063
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002064 /*
2065 * Wrong interface: drop packet and (maybe) send PIM assert.
2066 */
Yuval Mintzb70432f2018-02-28 23:29:32 +02002067 if (mrt->vif_table[vif].dev != skb->dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002068 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002069
Patrick McHardy6bd52142010-05-11 14:40:53 +02002070 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002071 /* pimsm uses asserts, when switching from RPT to SPT,
2072 so that we cannot check that packet arrived on an oif.
2073 It is bad, but otherwise we would need to move pretty
2074 large chunk of pimd to kernel. Ough... --ANK
2075 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002076 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02002077 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002078 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02002079 c->_c.mfc_un.res.last_assert +
2080 MFC_ASSERT_THRESH)) {
2081 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002082 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002083 }
2084 goto dont_forward;
2085 }
2086
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002087forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02002088 mrt->vif_table[vif].pkt_in++;
2089 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002090
2091 /*
2092 * Forward the frame
2093 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002094 if (ipv6_addr_any(&c->mf6c_origin) &&
2095 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002096 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002097 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002098 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02002099 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002100 /* It's an (*,*) entry and the packet is not coming from
2101 * the upstream: forward the packet to the upstream
2102 * only.
2103 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002104 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002105 goto last_forward;
2106 }
2107 goto dont_forward;
2108 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002109 for (ct = c->_c.mfc_un.res.maxvif - 1;
2110 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002111 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002112 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2113 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002114 if (psend != -1) {
2115 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2116 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002117 ip6mr_forward2(net, mrt, skb2,
2118 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002119 }
2120 psend = ct;
2121 }
2122 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002123last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002124 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002125 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002126 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002127 }
2128
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002129dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002130 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002131}
2132
2133
2134/*
2135 * Multicast packets for forwarding arrive here
2136 */
2137
2138int ip6_mr_input(struct sk_buff *skb)
2139{
2140 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002141 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002142 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002143 struct flowi6 fl6 = {
2144 .flowi6_iif = skb->dev->ifindex,
2145 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002146 };
2147 int err;
2148
David S. Miller4c9483b2011-03-12 16:22:43 -05002149 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002150 if (err < 0) {
2151 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002152 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002153 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002154
2155 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002156 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002157 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002158 if (!cache) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002159 int vif = ip6mr_find_vif(mrt, skb->dev);
2160
2161 if (vif >= 0)
2162 cache = ip6mr_cache_find_any(mrt,
2163 &ipv6_hdr(skb)->daddr,
2164 vif);
2165 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002166
2167 /*
2168 * No usable cache entry
2169 */
Ian Morris63159f22015-03-29 14:00:04 +01002170 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002171 int vif;
2172
Patrick McHardy6bd52142010-05-11 14:40:53 +02002173 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002174 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002175 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002176 read_unlock(&mrt_lock);
2177
2178 return err;
2179 }
2180 read_unlock(&mrt_lock);
2181 kfree_skb(skb);
2182 return -ENODEV;
2183 }
2184
Patrick McHardy6bd52142010-05-11 14:40:53 +02002185 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002186
2187 read_unlock(&mrt_lock);
2188
2189 return 0;
2190}
2191
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002192int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002193 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002194{
2195 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002196 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002197 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002198 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002199
Patrick McHardyd1db2752010-05-11 14:40:55 +02002200 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002201 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002202 return -ENOENT;
2203
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002204 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002205 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002206 if (!cache && skb->dev) {
2207 int vif = ip6mr_find_vif(mrt, skb->dev);
2208
2209 if (vif >= 0)
2210 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2211 vif);
2212 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002213
2214 if (!cache) {
2215 struct sk_buff *skb2;
2216 struct ipv6hdr *iph;
2217 struct net_device *dev;
2218 int vif;
2219
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002220 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002221 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002222 read_unlock(&mrt_lock);
2223 return -ENODEV;
2224 }
2225
2226 /* really correct? */
2227 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2228 if (!skb2) {
2229 read_unlock(&mrt_lock);
2230 return -ENOMEM;
2231 }
2232
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002233 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002234 skb_reset_transport_header(skb2);
2235
2236 skb_put(skb2, sizeof(struct ipv6hdr));
2237 skb_reset_network_header(skb2);
2238
2239 iph = ipv6_hdr(skb2);
2240 iph->version = 0;
2241 iph->priority = 0;
2242 iph->flow_lbl[0] = 0;
2243 iph->flow_lbl[1] = 0;
2244 iph->flow_lbl[2] = 0;
2245 iph->payload_len = 0;
2246 iph->nexthdr = IPPROTO_NONE;
2247 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002248 iph->saddr = rt->rt6i_src.addr;
2249 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002250
Patrick McHardy6bd52142010-05-11 14:40:53 +02002251 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002252 read_unlock(&mrt_lock);
2253
2254 return err;
2255 }
2256
Yuval Mintz7b0db852018-02-28 23:29:39 +02002257 err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002258 read_unlock(&mrt_lock);
2259 return err;
2260}
2261
Yuval Mintzb70432f2018-02-28 23:29:32 +02002262static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002263 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2264 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002265{
2266 struct nlmsghdr *nlh;
2267 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002268 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002269
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002270 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002271 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002272 return -EMSGSIZE;
2273
2274 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002275 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002276 rtm->rtm_dst_len = 128;
2277 rtm->rtm_src_len = 128;
2278 rtm->rtm_tos = 0;
2279 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002280 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2281 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002282 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002283 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002284 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002285 rtm->rtm_protocol = RTPROT_STATIC;
2286 else
2287 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002288 rtm->rtm_flags = 0;
2289
Jiri Benc930345e2015-03-29 16:59:25 +02002290 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2291 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002292 goto nla_put_failure;
Yuval Mintz7b0db852018-02-28 23:29:39 +02002293 err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002294 /* do not break the dump if cache is unresolved */
2295 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002296 goto nla_put_failure;
2297
Johannes Berg053c0952015-01-16 22:09:00 +01002298 nlmsg_end(skb, nlh);
2299 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002300
2301nla_put_failure:
2302 nlmsg_cancel(skb, nlh);
2303 return -EMSGSIZE;
2304}
2305
Yuval Mintz7b0db852018-02-28 23:29:39 +02002306static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
2307 u32 portid, u32 seq, struct mr_mfc *c,
2308 int cmd, int flags)
2309{
2310 return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c,
2311 cmd, flags);
2312}
2313
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002314static int mr6_msgsize(bool unresolved, int maxvif)
2315{
2316 size_t len =
2317 NLMSG_ALIGN(sizeof(struct rtmsg))
2318 + nla_total_size(4) /* RTA_TABLE */
2319 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2320 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2321 ;
2322
2323 if (!unresolved)
2324 len = len
2325 + nla_total_size(4) /* RTA_IIF */
2326 + nla_total_size(0) /* RTA_MULTIPATH */
2327 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2328 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002329 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002330 ;
2331
2332 return len;
2333}
2334
Yuval Mintzb70432f2018-02-28 23:29:32 +02002335static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002336 int cmd)
2337{
2338 struct net *net = read_pnet(&mrt->net);
2339 struct sk_buff *skb;
2340 int err = -ENOBUFS;
2341
Yuval Mintz494fff52018-02-28 23:29:34 +02002342 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002343 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002344 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002345 goto errout;
2346
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002347 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002348 if (err < 0)
2349 goto errout;
2350
2351 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2352 return;
2353
2354errout:
2355 kfree_skb(skb);
2356 if (err < 0)
2357 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2358}
2359
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002360static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2361{
2362 size_t len =
2363 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2364 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2365 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2366 /* IP6MRA_CREPORT_SRC_ADDR */
2367 + nla_total_size(sizeof(struct in6_addr))
2368 /* IP6MRA_CREPORT_DST_ADDR */
2369 + nla_total_size(sizeof(struct in6_addr))
2370 /* IP6MRA_CREPORT_PKT */
2371 + nla_total_size(payloadlen)
2372 ;
2373
2374 return len;
2375}
2376
Yuval Mintzb70432f2018-02-28 23:29:32 +02002377static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002378{
2379 struct net *net = read_pnet(&mrt->net);
2380 struct nlmsghdr *nlh;
2381 struct rtgenmsg *rtgenm;
2382 struct mrt6msg *msg;
2383 struct sk_buff *skb;
2384 struct nlattr *nla;
2385 int payloadlen;
2386
2387 payloadlen = pkt->len - sizeof(struct mrt6msg);
2388 msg = (struct mrt6msg *)skb_transport_header(pkt);
2389
2390 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2391 if (!skb)
2392 goto errout;
2393
2394 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2395 sizeof(struct rtgenmsg), 0);
2396 if (!nlh)
2397 goto errout;
2398 rtgenm = nlmsg_data(nlh);
2399 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2400 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2401 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2402 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2403 &msg->im6_src) ||
2404 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2405 &msg->im6_dst))
2406 goto nla_put_failure;
2407
2408 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2409 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2410 nla_data(nla), payloadlen))
2411 goto nla_put_failure;
2412
2413 nlmsg_end(skb, nlh);
2414
2415 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2416 return;
2417
2418nla_put_failure:
2419 nlmsg_cancel(skb, nlh);
2420errout:
2421 kfree_skb(skb);
2422 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2423}
2424
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002425static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2426{
Yuval Mintz7b0db852018-02-28 23:29:39 +02002427 return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
2428 _ip6mr_fill_mroute, &mfc_unres_lock);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002429}