blob: ddd9e6bba499ff3930025af9ae5a317a2188861d [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 int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Patrick McHardy5b285ca2010-05-11 14:40:56 +020091 struct mfc6_cache *c, struct rtmsg *rtm);
Yuval Mintzb70432f2018-02-28 23:29:32 +020092static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +000093 int cmd);
Yuval Mintzb70432f2018-02-28 23:29:32 +020094static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
Patrick McHardy5b285ca2010-05-11 14:40:56 +020095static int ip6mr_rtm_dumproute(struct sk_buff *skb,
96 struct netlink_callback *cb);
Yuval Mintzb70432f2018-02-28 23:29:32 +020097static void mroute_clean_tables(struct mr_table *mrt, bool all);
Kees Cooke99e88a2017-10-16 14:43:17 -070098static void ipmr_expire_process(struct timer_list *t);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +090099
Patrick McHardyd1db2752010-05-11 14:40:55 +0200100#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
Eric Dumazet8ffb3352010-06-06 15:34:40 -0700101#define ip6mr_for_each_table(mrt, net) \
Patrick McHardyd1db2752010-05-11 14:40:55 +0200102 list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
103
Yuval Mintzb70432f2018-02-28 23:29:32 +0200104static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200105{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200106 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200107
108 ip6mr_for_each_table(mrt, net) {
109 if (mrt->id == id)
110 return mrt;
111 }
112 return NULL;
113}
114
David S. Miller4c9483b2011-03-12 16:22:43 -0500115static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200116 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200117{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200118 int err;
Hannes Frederic Sowa95f4a452014-01-13 02:45:22 +0100119 struct ip6mr_result res;
120 struct fib_lookup_arg arg = {
121 .result = &res,
122 .flags = FIB_LOOKUP_NOREF,
123 };
Patrick McHardyd1db2752010-05-11 14:40:55 +0200124
David S. Miller4c9483b2011-03-12 16:22:43 -0500125 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
126 flowi6_to_flowi(flp6), 0, &arg);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200127 if (err < 0)
128 return err;
129 *mrt = res.mrt;
130 return 0;
131}
132
133static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
134 int flags, struct fib_lookup_arg *arg)
135{
136 struct ip6mr_result *res = arg->result;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200137 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200138
139 switch (rule->action) {
140 case FR_ACT_TO_TBL:
141 break;
142 case FR_ACT_UNREACHABLE:
143 return -ENETUNREACH;
144 case FR_ACT_PROHIBIT:
145 return -EACCES;
146 case FR_ACT_BLACKHOLE:
147 default:
148 return -EINVAL;
149 }
150
151 mrt = ip6mr_get_table(rule->fr_net, rule->table);
Ian Morris63159f22015-03-29 14:00:04 +0100152 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200153 return -EAGAIN;
154 res->mrt = mrt;
155 return 0;
156}
157
158static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
159{
160 return 1;
161}
162
163static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
164 FRA_GENERIC_POLICY,
165};
166
167static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
168 struct fib_rule_hdr *frh, struct nlattr **tb)
169{
170 return 0;
171}
172
173static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
174 struct nlattr **tb)
175{
176 return 1;
177}
178
179static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
180 struct fib_rule_hdr *frh)
181{
182 frh->dst_len = 0;
183 frh->src_len = 0;
184 frh->tos = 0;
185 return 0;
186}
187
Andi Kleen04a6f822012-10-04 17:12:11 -0700188static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200189 .family = RTNL_FAMILY_IP6MR,
190 .rule_size = sizeof(struct ip6mr_rule),
191 .addr_size = sizeof(struct in6_addr),
192 .action = ip6mr_rule_action,
193 .match = ip6mr_rule_match,
194 .configure = ip6mr_rule_configure,
195 .compare = ip6mr_rule_compare,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200196 .fill = ip6mr_rule_fill,
197 .nlgroup = RTNLGRP_IPV6_RULE,
198 .policy = ip6mr_rule_policy,
199 .owner = THIS_MODULE,
200};
201
202static int __net_init ip6mr_rules_init(struct net *net)
203{
204 struct fib_rules_ops *ops;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200205 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200206 int err;
207
208 ops = fib_rules_register(&ip6mr_rules_ops_template, net);
209 if (IS_ERR(ops))
210 return PTR_ERR(ops);
211
212 INIT_LIST_HEAD(&net->ipv6.mr6_tables);
213
214 mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100215 if (!mrt) {
Patrick McHardyd1db2752010-05-11 14:40:55 +0200216 err = -ENOMEM;
217 goto err1;
218 }
219
220 err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
221 if (err < 0)
222 goto err2;
223
224 net->ipv6.mr6_rules_ops = ops;
225 return 0;
226
227err2:
WANG Congf243e5a2015-03-25 14:45:03 -0700228 ip6mr_free_table(mrt);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200229err1:
230 fib_rules_unregister(ops);
231 return err;
232}
233
234static void __net_exit ip6mr_rules_exit(struct net *net)
235{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200236 struct mr_table *mrt, *next;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200237
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200238 rtnl_lock();
Eric Dumazet035320d2010-06-06 23:48:40 +0000239 list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
240 list_del(&mrt->list);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200241 ip6mr_free_table(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000242 }
Patrick McHardyd1db2752010-05-11 14:40:55 +0200243 fib_rules_unregister(net->ipv6.mr6_rules_ops);
WANG Cong419df122015-03-31 11:01:46 -0700244 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200245}
246#else
247#define ip6mr_for_each_table(mrt, net) \
248 for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
249
Yuval Mintzb70432f2018-02-28 23:29:32 +0200250static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200251{
252 return net->ipv6.mrt6;
253}
254
David S. Miller4c9483b2011-03-12 16:22:43 -0500255static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
Yuval Mintzb70432f2018-02-28 23:29:32 +0200256 struct mr_table **mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200257{
258 *mrt = net->ipv6.mrt6;
259 return 0;
260}
261
262static int __net_init ip6mr_rules_init(struct net *net)
263{
264 net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
265 return net->ipv6.mrt6 ? 0 : -ENOMEM;
266}
267
268static void __net_exit ip6mr_rules_exit(struct net *net)
269{
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200270 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200271 ip6mr_free_table(net->ipv6.mrt6);
Hannes Frederic Sowa905a6f92013-07-22 23:45:53 +0200272 net->ipv6.mrt6 = NULL;
273 rtnl_unlock();
Patrick McHardyd1db2752010-05-11 14:40:55 +0200274}
275#endif
276
Yuval Mintz87c418b2018-02-28 23:29:31 +0200277static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
278 const void *ptr)
279{
280 const struct mfc6_cache_cmp_arg *cmparg = arg->key;
281 struct mfc6_cache *c = (struct mfc6_cache *)ptr;
282
283 return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) ||
284 !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin);
285}
286
287static const struct rhashtable_params ip6mr_rht_params = {
Yuval Mintz494fff52018-02-28 23:29:34 +0200288 .head_offset = offsetof(struct mr_mfc, mnode),
Yuval Mintz87c418b2018-02-28 23:29:31 +0200289 .key_offset = offsetof(struct mfc6_cache, cmparg),
290 .key_len = sizeof(struct mfc6_cache_cmp_arg),
291 .nelem_hint = 3,
292 .locks_mul = 1,
293 .obj_cmpfn = ip6mr_hash_cmp,
294 .automatic_shrinking = true,
295};
296
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200297static void ip6mr_new_table_set(struct mr_table *mrt,
298 struct net *net)
299{
300#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
301 list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
302#endif
303}
304
Yuval Mintz845c9a72018-02-28 23:29:35 +0200305static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = {
306 .mf6c_origin = IN6ADDR_ANY_INIT,
307 .mf6c_mcastgrp = IN6ADDR_ANY_INIT,
308};
309
310static struct mr_table_ops ip6mr_mr_table_ops = {
311 .rht_params = &ip6mr_rht_params,
312 .cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
313};
314
Yuval Mintzb70432f2018-02-28 23:29:32 +0200315static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200316{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200317 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200318
319 mrt = ip6mr_get_table(net, id);
Ian Morris53b24b82015-03-29 14:00:05 +0100320 if (mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200321 return mrt;
322
Yuval Mintz845c9a72018-02-28 23:29:35 +0200323 return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
Yuval Mintz0bbbf0e2018-02-28 23:29:33 +0200324 ipmr_expire_process, ip6mr_new_table_set);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200325}
326
Yuval Mintzb70432f2018-02-28 23:29:32 +0200327static void ip6mr_free_table(struct mr_table *mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200328{
WANG Cong7ba0c472015-03-31 11:01:47 -0700329 del_timer_sync(&mrt->ipmr_expire_timer);
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +0100330 mroute_clean_tables(mrt, true);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200331 rhltable_destroy(&mrt->mfc_hash);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200332 kfree(mrt);
333}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900334
335#ifdef CONFIG_PROC_FS
Yuval Mintzc8d61962018-02-28 23:29:36 +0200336/* The /proc interfaces to multicast routing
337 * /proc/ip6_mr_cache /proc/ip6_mr_vif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900338 */
339
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900340static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
341 __acquires(mrt_lock)
342{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200343 struct mr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800344 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200345 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200346
347 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100348 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200349 return ERR_PTR(-ENOENT);
350
351 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800352
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900353 read_lock(&mrt_lock);
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200354 return mr_vif_seq_start(seq, pos);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900355}
356
357static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
358 __releases(mrt_lock)
359{
360 read_unlock(&mrt_lock);
361}
362
363static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
364{
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200365 struct mr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200366 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800367
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900368 if (v == SEQ_START_TOKEN) {
369 seq_puts(seq,
370 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
371 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200372 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900373 const char *name = vif->dev ? vif->dev->name : "none";
374
375 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100376 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200377 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900378 name, vif->bytes_in, vif->pkt_in,
379 vif->bytes_out, vif->pkt_out,
380 vif->flags);
381 }
382 return 0;
383}
384
Stephen Hemminger98147d52009-09-01 19:25:02 +0000385static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900386 .start = ip6mr_vif_seq_start,
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200387 .next = mr_vif_seq_next,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900388 .stop = ip6mr_vif_seq_stop,
389 .show = ip6mr_vif_seq_show,
390};
391
392static int ip6mr_vif_open(struct inode *inode, struct file *file)
393{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800394 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
Yuval Mintz3feda6b2018-02-28 23:29:37 +0200395 sizeof(struct mr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900396}
397
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000398static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900399 .open = ip6mr_vif_open,
400 .read = seq_read,
401 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800402 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900403};
404
405static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
406{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800407 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200408 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800409
Patrick McHardyd1db2752010-05-11 14:40:55 +0200410 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100411 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200412 return ERR_PTR(-ENOENT);
413
Yuval Mintzc8d61962018-02-28 23:29:36 +0200414 return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900415}
416
417static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
418{
419 int n;
420
421 if (v == SEQ_START_TOKEN) {
422 seq_puts(seq,
423 "Group "
424 "Origin "
425 "Iif Pkts Bytes Wrong Oifs\n");
426 } else {
427 const struct mfc6_cache *mfc = v;
Yuval Mintzc8d61962018-02-28 23:29:36 +0200428 const struct mr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200429 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900430
Benjamin Thery999890b22008-12-03 22:22:16 -0800431 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700432 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200433 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900434
Yuval Mintzb70432f2018-02-28 23:29:32 +0200435 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800436 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200437 mfc->_c.mfc_un.res.pkt,
438 mfc->_c.mfc_un.res.bytes,
439 mfc->_c.mfc_un.res.wrong_if);
440 for (n = mfc->_c.mfc_un.res.minvif;
441 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200442 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200443 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900444 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200445 " %2d:%-3d", n,
446 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900447 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800448 } else {
449 /* unresolved mfc_caches don't contain
450 * pkt, bytes and wrong_if values
451 */
452 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900453 }
454 seq_putc(seq, '\n');
455 }
456 return 0;
457}
458
James Morris88e9d342009-09-22 16:43:43 -0700459static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900460 .start = ipmr_mfc_seq_start,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200461 .next = mr_mfc_seq_next,
462 .stop = mr_mfc_seq_stop,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900463 .show = ipmr_mfc_seq_show,
464};
465
466static int ipmr_mfc_open(struct inode *inode, struct file *file)
467{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800468 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200469 sizeof(struct mr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900470}
471
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000472static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900473 .open = ipmr_mfc_open,
474 .read = seq_read,
475 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800476 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900477};
478#endif
479
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900480#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900481
482static int pim6_rcv(struct sk_buff *skb)
483{
484 struct pimreghdr *pim;
485 struct ipv6hdr *encap;
486 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800487 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200488 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500489 struct flowi6 fl6 = {
490 .flowi6_iif = skb->dev->ifindex,
491 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200492 };
493 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900494
495 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
496 goto drop;
497
498 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100499 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900500 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800501 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
502 sizeof(*pim), IPPROTO_PIM,
503 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700504 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900505 goto drop;
506
507 /* check if the inner packet is destined to mcast group */
508 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
509 sizeof(*pim));
510
511 if (!ipv6_addr_is_multicast(&encap->daddr) ||
512 encap->payload_len == 0 ||
513 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
514 goto drop;
515
David S. Miller4c9483b2011-03-12 16:22:43 -0500516 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200517 goto drop;
518 reg_vif_num = mrt->mroute_reg_vif_num;
519
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900520 read_lock(&mrt_lock);
521 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200522 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900523 if (reg_dev)
524 dev_hold(reg_dev);
525 read_unlock(&mrt_lock);
526
Ian Morris63159f22015-03-29 14:00:04 +0100527 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900528 goto drop;
529
530 skb->mac_header = skb->network_header;
531 skb_pull(skb, (u8 *)encap - skb->data);
532 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800533 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000534 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700535
Nicolas Dichtelea231922013-09-02 15:34:58 +0200536 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700537
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000538 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000539
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900540 dev_put(reg_dev);
541 return 0;
542 drop:
543 kfree_skb(skb);
544 return 0;
545}
546
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000547static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900548 .handler = pim6_rcv,
549};
550
551/* Service routines creating virtual interfaces: PIMREG */
552
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000553static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
554 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900555{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800556 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200557 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500558 struct flowi6 fl6 = {
559 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700560 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500561 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200562 };
563 int err;
564
David S. Miller4c9483b2011-03-12 16:22:43 -0500565 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000566 if (err < 0) {
567 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200568 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000569 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800570
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900571 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700572 dev->stats.tx_bytes += skb->len;
573 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200574 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900575 read_unlock(&mrt_lock);
576 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000577 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900578}
579
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200580static int reg_vif_get_iflink(const struct net_device *dev)
581{
582 return 0;
583}
584
Stephen Hemminger007c3832008-11-20 20:28:35 -0800585static const struct net_device_ops reg_vif_netdev_ops = {
586 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200587 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800588};
589
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900590static void reg_vif_setup(struct net_device *dev)
591{
592 dev->type = ARPHRD_PIMREG;
593 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
594 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800595 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400596 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700597 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900598}
599
Yuval Mintzb70432f2018-02-28 23:29:32 +0200600static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900601{
602 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200603 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900604
Patrick McHardyd1db2752010-05-11 14:40:55 +0200605 if (mrt->id == RT6_TABLE_DFLT)
606 sprintf(name, "pim6reg");
607 else
608 sprintf(name, "pim6reg%u", mrt->id);
609
Tom Gundersenc835a672014-07-14 16:37:24 +0200610 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100611 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900612 return NULL;
613
Benjamin Thery8229efd2008-12-10 16:30:15 -0800614 dev_net_set(dev, net);
615
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900616 if (register_netdevice(dev)) {
617 free_netdev(dev);
618 return NULL;
619 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900620
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900621 if (dev_open(dev))
622 goto failure;
623
Wang Chen7af3db72008-07-14 20:54:54 -0700624 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900625 return dev;
626
627failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900628 unregister_netdevice(dev);
629 return NULL;
630}
631#endif
632
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900633/*
634 * Delete a VIF entry
635 */
636
Yuval Mintzb70432f2018-02-28 23:29:32 +0200637static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300638 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900639{
Yuval Mintz6853f212018-02-28 23:29:29 +0200640 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900641 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800642 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200643
644 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900645 return -EADDRNOTAVAIL;
646
Yuval Mintzb70432f2018-02-28 23:29:32 +0200647 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900648
649 write_lock_bh(&mrt_lock);
650 dev = v->dev;
651 v->dev = NULL;
652
653 if (!dev) {
654 write_unlock_bh(&mrt_lock);
655 return -EADDRNOTAVAIL;
656 }
657
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900658#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200659 if (vifi == mrt->mroute_reg_vif_num)
660 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900661#endif
662
Patrick McHardy6bd52142010-05-11 14:40:53 +0200663 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900664 int tmp;
665 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200666 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900667 break;
668 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200669 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900670 }
671
672 write_unlock_bh(&mrt_lock);
673
674 dev_set_allmulti(dev, -1);
675
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800676 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000677 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800678 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700679 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000680 NETCONFA_MC_FORWARDING,
681 dev->ifindex, &in6_dev->cnf);
682 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800683
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300684 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000685 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900686
687 dev_put(dev);
688 return 0;
689}
690
Yuval Mintz87c418b2018-02-28 23:29:31 +0200691static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
692{
Yuval Mintz494fff52018-02-28 23:29:34 +0200693 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200694
Yuval Mintz494fff52018-02-28 23:29:34 +0200695 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200696}
697
Benjamin Thery58701ad2008-12-10 16:22:34 -0800698static inline void ip6mr_cache_free(struct mfc6_cache *c)
699{
Yuval Mintz494fff52018-02-28 23:29:34 +0200700 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800701}
702
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900703/* Destroy an unresolved cache entry, killing queued skbs
704 and reporting error to netlink readers.
705 */
706
Yuval Mintzb70432f2018-02-28 23:29:32 +0200707static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900708{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200709 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900710 struct sk_buff *skb;
711
Patrick McHardy6bd52142010-05-11 14:40:53 +0200712 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900713
Yuval Mintz494fff52018-02-28 23:29:34 +0200714 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900715 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200716 struct nlmsghdr *nlh = skb_pull(skb,
717 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900718 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000719 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900720 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000721 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000722 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900723 } else
724 kfree_skb(skb);
725 }
726
Benjamin Thery58701ad2008-12-10 16:22:34 -0800727 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900728}
729
730
Patrick McHardyc476efb2010-05-11 14:40:48 +0200731/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900732
Yuval Mintzb70432f2018-02-28 23:29:32 +0200733static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900734{
735 unsigned long now = jiffies;
736 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200737 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900738
Yuval Mintzb70432f2018-02-28 23:29:32 +0200739 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900740 if (time_after(c->mfc_un.unres.expires, now)) {
741 /* not yet... */
742 unsigned long interval = c->mfc_un.unres.expires - now;
743 if (interval < expires)
744 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900745 continue;
746 }
747
Patrick McHardyf30a77842010-05-11 14:40:51 +0200748 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200749 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
750 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900751 }
752
Yuval Mintzb70432f2018-02-28 23:29:32 +0200753 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200754 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900755}
756
Kees Cooke99e88a2017-10-16 14:43:17 -0700757static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900758{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200759 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200760
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900761 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200762 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900763 return;
764 }
765
Yuval Mintzb70432f2018-02-28 23:29:32 +0200766 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200767 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900768
769 spin_unlock(&mfc_unres_lock);
770}
771
772/* Fill oifs list. It is called under write locked mrt_lock. */
773
Yuval Mintzb70432f2018-02-28 23:29:32 +0200774static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200775 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200776 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900777{
778 int vifi;
779
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300780 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900781 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300782 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900783
Patrick McHardy6bd52142010-05-11 14:40:53 +0200784 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200785 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800786 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900787 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
788 if (cache->mfc_un.res.minvif > vifi)
789 cache->mfc_un.res.minvif = vifi;
790 if (cache->mfc_un.res.maxvif <= vifi)
791 cache->mfc_un.res.maxvif = vifi + 1;
792 }
793 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200794 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900795}
796
Yuval Mintzb70432f2018-02-28 23:29:32 +0200797static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200798 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900799{
800 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200801 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900802 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800803 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700804 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900805
806 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200807 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900808 return -EADDRINUSE;
809
810 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900811#ifdef CONFIG_IPV6_PIMSM_V2
812 case MIFF_REGISTER:
813 /*
814 * Special Purpose VIF in PIM
815 * All the packets will be sent to the daemon
816 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200817 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900818 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200819 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900820 if (!dev)
821 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700822 err = dev_set_allmulti(dev, 1);
823 if (err) {
824 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700825 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700826 return err;
827 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900828 break;
829#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900830 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800831 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900832 if (!dev)
833 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700834 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700835 if (err) {
836 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700837 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700838 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900839 break;
840 default:
841 return -EINVAL;
842 }
843
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800844 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000845 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800846 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700847 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000848 NETCONFA_MC_FORWARDING,
849 dev->ifindex, &in6_dev->cnf);
850 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800851
Yuval Mintz6853f212018-02-28 23:29:29 +0200852 /* Fill in the VIF structures */
853 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
854 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
855 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900856
857 /* And finish update writing critical data */
858 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900859 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900860#ifdef CONFIG_IPV6_PIMSM_V2
861 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200862 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900863#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200864 if (vifi + 1 > mrt->maxvif)
865 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900866 write_unlock_bh(&mrt_lock);
867 return 0;
868}
869
Yuval Mintzb70432f2018-02-28 23:29:32 +0200870static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000871 const struct in6_addr *origin,
872 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900873{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200874 struct mfc6_cache_cmp_arg arg = {
875 .mf6c_origin = *origin,
876 .mf6c_mcastgrp = *mcastgrp,
877 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900878
Yuval Mintz845c9a72018-02-28 23:29:35 +0200879 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000880}
881
882/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200883static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000884 struct in6_addr *mcastgrp,
885 mifi_t mifi)
886{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200887 struct mfc6_cache_cmp_arg arg = {
888 .mf6c_origin = in6addr_any,
889 .mf6c_mcastgrp = *mcastgrp,
890 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000891
892 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +0200893 return mr_mfc_find_any_parent(mrt, mifi);
894 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000895}
896
Yuval Mintz87c418b2018-02-28 23:29:31 +0200897/* Look for a (S,G,iif) entry if parent != -1 */
898static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +0200899ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +0200900 const struct in6_addr *origin,
901 const struct in6_addr *mcastgrp,
902 int parent)
903{
904 struct mfc6_cache_cmp_arg arg = {
905 .mf6c_origin = *origin,
906 .mf6c_mcastgrp = *mcastgrp,
907 };
Yuval Mintz87c418b2018-02-28 23:29:31 +0200908
Yuval Mintz845c9a72018-02-28 23:29:35 +0200909 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200910}
911
Yuval Mintz845c9a72018-02-28 23:29:35 +0200912/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200913static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900914{
Joe Perches36cbac52008-12-03 22:27:25 -0800915 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100916 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900917 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200918 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
919 c->_c.mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900920 return c;
921}
922
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200923static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900924{
Joe Perches36cbac52008-12-03 22:27:25 -0800925 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +0100926 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900927 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200928 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
929 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900930 return c;
931}
932
933/*
934 * A cache entry has gone into a resolved state from queued
935 */
936
Yuval Mintzb70432f2018-02-28 23:29:32 +0200937static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200938 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900939{
940 struct sk_buff *skb;
941
942 /*
943 * Play the pending entries through our router
944 */
945
Yuval Mintz494fff52018-02-28 23:29:34 +0200946 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900947 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200948 struct nlmsghdr *nlh = skb_pull(skb,
949 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900950
Hong zhi guo573ce262013-03-27 06:47:04 +0000951 if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +0900952 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900953 } else {
954 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000955 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900956 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000957 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900958 }
Eric W. Biederman15e47302012-09-07 20:12:54 +0000959 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900960 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +0200961 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900962 }
963}
964
965/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -0700966 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900967 *
968 * Called under mrt_lock.
969 */
970
Yuval Mintzb70432f2018-02-28 23:29:32 +0200971static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200972 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900973{
Yuval Mintz8571ab42018-02-28 23:29:30 +0200974 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900975 struct sk_buff *skb;
976 struct mrt6msg *msg;
977 int ret;
978
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900979#ifdef CONFIG_IPV6_PIMSM_V2
980 if (assert == MRT6MSG_WHOLEPKT)
981 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
982 +sizeof(*msg));
983 else
984#endif
985 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900986
987 if (!skb)
988 return -ENOBUFS;
989
990 /* I suppose that internal messages
991 * do not require checksums */
992
993 skb->ip_summed = CHECKSUM_UNNECESSARY;
994
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900995#ifdef CONFIG_IPV6_PIMSM_V2
996 if (assert == MRT6MSG_WHOLEPKT) {
997 /* Ugly, but we have no choice with this interface.
998 Duplicate old header, fix length etc.
999 And all this only to mangle msg->im6_msgtype and
1000 to set msg->im6_mbz to "mbz" :-)
1001 */
1002 skb_push(skb, -skb_network_offset(pkt));
1003
1004 skb_push(skb, sizeof(*msg));
1005 skb_reset_transport_header(skb);
1006 msg = (struct mrt6msg *)skb_transport_header(skb);
1007 msg->im6_mbz = 0;
1008 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001009 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001010 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001011 msg->im6_src = ipv6_hdr(pkt)->saddr;
1012 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001013
1014 skb->ip_summed = CHECKSUM_UNNECESSARY;
1015 } else
1016#endif
1017 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001018 /*
1019 * Copy the IP header
1020 */
1021
1022 skb_put(skb, sizeof(struct ipv6hdr));
1023 skb_reset_network_header(skb);
1024 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1025
1026 /*
1027 * Add our header
1028 */
1029 skb_put(skb, sizeof(*msg));
1030 skb_reset_transport_header(skb);
1031 msg = (struct mrt6msg *)skb_transport_header(skb);
1032
1033 msg->im6_mbz = 0;
1034 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001035 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001036 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001037 msg->im6_src = ipv6_hdr(pkt)->saddr;
1038 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001039
Eric Dumazetadf30902009-06-02 05:19:30 +00001040 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001041 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001042 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001043
Yuval Mintz8571ab42018-02-28 23:29:30 +02001044 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001045 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001046 if (!mroute6_sk) {
1047 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001048 kfree_skb(skb);
1049 return -EINVAL;
1050 }
1051
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001052 mrt6msg_netlink_event(mrt, skb);
1053
Yuval Mintz8571ab42018-02-28 23:29:30 +02001054 /* Deliver to user space multicast routing algorithms */
1055 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1056 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001057 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001058 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001059 kfree_skb(skb);
1060 }
1061
1062 return ret;
1063}
1064
Yuval Mintz494fff52018-02-28 23:29:34 +02001065/* Queue a packet for resolution. It gets locked cache entry! */
1066static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
1067 struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001068{
Yuval Mintz494fff52018-02-28 23:29:34 +02001069 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001070 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001071 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001072
1073 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001074 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001075 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001076 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1077 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001078 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001079 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001080 }
1081
Patrick McHardyf30a77842010-05-11 14:40:51 +02001082 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001083 /*
1084 * Create a new entry if allowable
1085 */
1086
Patrick McHardy6bd52142010-05-11 14:40:53 +02001087 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001088 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001089 spin_unlock_bh(&mfc_unres_lock);
1090
1091 kfree_skb(skb);
1092 return -ENOBUFS;
1093 }
1094
Yuval Mintz494fff52018-02-28 23:29:34 +02001095 /* Fill in the new cache entry */
1096 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001097 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1098 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1099
1100 /*
1101 * Reflect first query at pim6sd
1102 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001103 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001104 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001105 /* If the report failed throw the cache entry
1106 out - Brad Parker
1107 */
1108 spin_unlock_bh(&mfc_unres_lock);
1109
Benjamin Thery58701ad2008-12-10 16:22:34 -08001110 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001111 kfree_skb(skb);
1112 return err;
1113 }
1114
Patrick McHardy6bd52142010-05-11 14:40:53 +02001115 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001116 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001117 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001118
Patrick McHardy6bd52142010-05-11 14:40:53 +02001119 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001120 }
1121
Yuval Mintz494fff52018-02-28 23:29:34 +02001122 /* See if we can append the packet */
1123 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001124 kfree_skb(skb);
1125 err = -ENOBUFS;
1126 } else {
Yuval Mintz494fff52018-02-28 23:29:34 +02001127 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001128 err = 0;
1129 }
1130
1131 spin_unlock_bh(&mfc_unres_lock);
1132 return err;
1133}
1134
1135/*
1136 * MFC6 cache manipulation by user space
1137 */
1138
Yuval Mintzb70432f2018-02-28 23:29:32 +02001139static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001140 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001141{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001142 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001143
Yuval Mintz87c418b2018-02-28 23:29:31 +02001144 /* The entries are added/deleted only under RTNL */
1145 rcu_read_lock();
1146 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1147 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1148 rcu_read_unlock();
1149 if (!c)
1150 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001151 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1152 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001153
Yuval Mintz87c418b2018-02-28 23:29:31 +02001154 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1155 ip6mr_cache_free(c);
1156 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001157}
1158
1159static int ip6mr_device_event(struct notifier_block *this,
1160 unsigned long event, void *ptr)
1161{
Jiri Pirko351638e2013-05-28 01:30:21 +00001162 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001163 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001164 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001165 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001166 int ct;
1167
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001168 if (event != NETDEV_UNREGISTER)
1169 return NOTIFY_DONE;
1170
Patrick McHardyd1db2752010-05-11 14:40:55 +02001171 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001172 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001173 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1174 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001175 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001176 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001177 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001178
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001179 return NOTIFY_DONE;
1180}
1181
1182static struct notifier_block ip6_mr_notifier = {
1183 .notifier_call = ip6mr_device_event
1184};
1185
1186/*
1187 * Setup for IP multicast routing
1188 */
1189
Benjamin Thery4e168802008-12-10 16:15:08 -08001190static int __net_init ip6mr_net_init(struct net *net)
1191{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001192 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001193
Patrick McHardyd1db2752010-05-11 14:40:55 +02001194 err = ip6mr_rules_init(net);
1195 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001196 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001197
1198#ifdef CONFIG_PROC_FS
1199 err = -ENOMEM;
Gao fengd4beaa62013-02-18 01:34:54 +00001200 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001201 goto proc_vif_fail;
Gao fengd4beaa62013-02-18 01:34:54 +00001202 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001203 goto proc_cache_fail;
1204#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001205
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001206 return 0;
1207
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001208#ifdef CONFIG_PROC_FS
1209proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001210 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001211proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001212 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001213#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001214fail:
1215 return err;
1216}
1217
1218static void __net_exit ip6mr_net_exit(struct net *net)
1219{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001220#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001221 remove_proc_entry("ip6_mr_cache", net->proc_net);
1222 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001223#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001224 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001225}
1226
1227static struct pernet_operations ip6mr_net_ops = {
1228 .init = ip6mr_net_init,
1229 .exit = ip6mr_net_exit,
Kirill Tkhaib01a59a2018-02-19 11:48:37 +03001230 .async = true,
Benjamin Thery4e168802008-12-10 16:15:08 -08001231};
1232
Wang Chen623d1a12008-07-03 12:13:30 +08001233int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001234{
Wang Chen623d1a12008-07-03 12:13:30 +08001235 int err;
1236
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001237 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1238 sizeof(struct mfc6_cache),
1239 0, SLAB_HWCACHE_ALIGN,
1240 NULL);
1241 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001242 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001243
Benjamin Thery4e168802008-12-10 16:15:08 -08001244 err = register_pernet_subsys(&ip6mr_net_ops);
1245 if (err)
1246 goto reg_pernet_fail;
1247
Wang Chen623d1a12008-07-03 12:13:30 +08001248 err = register_netdevice_notifier(&ip6_mr_notifier);
1249 if (err)
1250 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001251#ifdef CONFIG_IPV6_PIMSM_V2
1252 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001253 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001254 err = -EAGAIN;
1255 goto add_proto_fail;
1256 }
1257#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001258 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1259 NULL, ip6mr_rtm_dumproute, 0);
1260 if (err == 0)
1261 return 0;
1262
Tom Goff403dbb92009-06-14 03:16:13 -07001263#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001264 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001265add_proto_fail:
1266 unregister_netdevice_notifier(&ip6_mr_notifier);
1267#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001268reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001269 unregister_pernet_subsys(&ip6mr_net_ops);
1270reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001271 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001272 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001273}
1274
Wang Chen623d1a12008-07-03 12:13:30 +08001275void ip6_mr_cleanup(void)
1276{
Duan Jiongffb13882014-11-19 09:35:39 +08001277 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1278#ifdef CONFIG_IPV6_PIMSM_V2
1279 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1280#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001281 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001282 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001283 kmem_cache_destroy(mrt_cachep);
1284}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001285
Yuval Mintzb70432f2018-02-28 23:29:32 +02001286static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001287 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001288{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001289 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001290 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001291 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001292 bool found;
1293 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001294
Patrick McHardya50436f22010-03-17 06:04:14 +00001295 if (mfc->mf6cc_parent >= MAXMIFS)
1296 return -ENFILE;
1297
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001298 memset(ttls, 255, MAXMIFS);
1299 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001300 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1301 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001302 }
1303
Yuval Mintz87c418b2018-02-28 23:29:31 +02001304 /* The entries are added/deleted only under RTNL */
1305 rcu_read_lock();
1306 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1307 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1308 rcu_read_unlock();
1309 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001310 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001311 c->_c.mfc_parent = mfc->mf6cc_parent;
1312 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001313 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001314 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001315 write_unlock_bh(&mrt_lock);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001316 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001317 return 0;
1318 }
1319
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001320 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1321 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001322 return -EINVAL;
1323
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001324 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001325 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001326 return -ENOMEM;
1327
1328 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1329 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001330 c->_c.mfc_parent = mfc->mf6cc_parent;
1331 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001332 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001333 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001334
Yuval Mintz494fff52018-02-28 23:29:34 +02001335 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001336 ip6mr_rht_params);
1337 if (err) {
1338 pr_err("ip6mr: rhtable insert error %d\n", err);
1339 ip6mr_cache_free(c);
1340 return err;
1341 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001342 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001343
Yuval Mintz87c418b2018-02-28 23:29:31 +02001344 /* Check to see if we resolved a queued list. If so we
1345 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001346 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001347 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001348 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001349 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1350 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001351 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001352 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001353 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001354 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001355 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001356 break;
1357 }
1358 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001359 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001360 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001361 spin_unlock_bh(&mfc_unres_lock);
1362
Patrick McHardyf30a77842010-05-11 14:40:51 +02001363 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001364 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001365 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001366 }
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001367 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001368 return 0;
1369}
1370
1371/*
1372 * Close the multicast socket, and clear the vif tables etc
1373 */
1374
Yuval Mintzb70432f2018-02-28 23:29:32 +02001375static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001376{
Yuval Mintz494fff52018-02-28 23:29:34 +02001377 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001378 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001379 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001380
Yuval Mintz87c418b2018-02-28 23:29:31 +02001381 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001382 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001383 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001384 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001385 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001386 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001387 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001388
Yuval Mintz87c418b2018-02-28 23:29:31 +02001389 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001390 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001391 if (!all && (c->mfc_flags & MFC_STATIC))
1392 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001393 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001394 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001395 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
1396 ip6mr_cache_free((struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001397 }
1398
Patrick McHardy6bd52142010-05-11 14:40:53 +02001399 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001400 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001401 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001402 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001403 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1404 RTM_DELROUTE);
1405 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001406 }
1407 spin_unlock_bh(&mfc_unres_lock);
1408 }
1409}
1410
Yuval Mintzb70432f2018-02-28 23:29:32 +02001411static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001412{
1413 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001414 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001415
1416 rtnl_lock();
1417 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001418 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001419 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001420 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001421 rcu_assign_pointer(mrt->mroute_sk, sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001422 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001423 }
1424 write_unlock_bh(&mrt_lock);
1425
1426 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001427 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1428 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001429 NETCONFA_IFINDEX_ALL,
1430 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001431 rtnl_unlock();
1432
1433 return err;
1434}
1435
1436int ip6mr_sk_done(struct sock *sk)
1437{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001438 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001439 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001440 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001441
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001442 if (sk->sk_type != SOCK_RAW ||
1443 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1444 return err;
1445
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001446 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001447 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001448 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001449 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001450 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001451 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001452 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001453 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001454 NETCONFA_MC_FORWARDING,
1455 NETCONFA_IFINDEX_ALL,
1456 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001457
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001458 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001459 err = 0;
1460 break;
1461 }
1462 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001463 rtnl_unlock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001464 synchronize_rcu();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001465
1466 return err;
1467}
1468
Yuval Mintz8571ab42018-02-28 23:29:30 +02001469bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001470{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001471 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001472 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001473 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001474 .flowi6_oif = skb->dev->ifindex,
1475 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001476 };
1477
David S. Miller4c9483b2011-03-12 16:22:43 -05001478 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001479 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001480
Yuval Mintzb70432f2018-02-28 23:29:32 +02001481 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001482}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001483EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001484
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001485/*
1486 * Socket options and virtual interface manipulation. The whole
1487 * virtual interface system is a complete heap, but unfortunately
1488 * that's how BSD mrouted happens to think. Maybe one day with a proper
1489 * MOSPF/PIM router set up we can clean this up.
1490 */
1491
David S. Millerb7058842009-09-30 16:12:20 -07001492int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001493{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001494 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001495 struct mif6ctl vif;
1496 struct mf6cctl mfc;
1497 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001498 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001499 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001500
Xin Long99253eb2017-02-24 16:29:06 +08001501 if (sk->sk_type != SOCK_RAW ||
1502 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1503 return -EOPNOTSUPP;
1504
Patrick McHardyd1db2752010-05-11 14:40:55 +02001505 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001506 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001507 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001508
1509 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001510 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001511 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001512 return -EACCES;
1513 }
1514
1515 switch (optname) {
1516 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001517 if (optlen < sizeof(int))
1518 return -EINVAL;
1519
Patrick McHardy6bd52142010-05-11 14:40:53 +02001520 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001521
1522 case MRT6_DONE:
1523 return ip6mr_sk_done(sk);
1524
1525 case MRT6_ADD_MIF:
1526 if (optlen < sizeof(vif))
1527 return -EINVAL;
1528 if (copy_from_user(&vif, optval, sizeof(vif)))
1529 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001530 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001531 return -ENFILE;
1532 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001533 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001534 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001535 rtnl_unlock();
1536 return ret;
1537
1538 case MRT6_DEL_MIF:
1539 if (optlen < sizeof(mifi_t))
1540 return -EINVAL;
1541 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1542 return -EFAULT;
1543 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001544 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001545 rtnl_unlock();
1546 return ret;
1547
1548 /*
1549 * Manipulate the forwarding caches. These live
1550 * in a sort of kernel/user symbiosis.
1551 */
1552 case MRT6_ADD_MFC:
1553 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001554 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001555 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001556 case MRT6_ADD_MFC_PROXY:
1557 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001558 if (optlen < sizeof(mfc))
1559 return -EINVAL;
1560 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1561 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001562 if (parent == 0)
1563 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001564 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001565 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1566 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001567 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001568 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001569 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001570 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001571 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001572 rtnl_unlock();
1573 return ret;
1574
1575 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001576 * Control PIM assert (to activate pim will activate assert)
1577 */
1578 case MRT6_ASSERT:
1579 {
1580 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001581
1582 if (optlen != sizeof(v))
1583 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001584 if (get_user(v, (int __user *)optval))
1585 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001586 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001587 return 0;
1588 }
1589
1590#ifdef CONFIG_IPV6_PIMSM_V2
1591 case MRT6_PIM:
1592 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001593 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001594
1595 if (optlen != sizeof(v))
1596 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001597 if (get_user(v, (int __user *)optval))
1598 return -EFAULT;
1599 v = !!v;
1600 rtnl_lock();
1601 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001602 if (v != mrt->mroute_do_pim) {
1603 mrt->mroute_do_pim = v;
1604 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001605 }
1606 rtnl_unlock();
1607 return ret;
1608 }
1609
1610#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001611#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1612 case MRT6_TABLE:
1613 {
1614 u32 v;
1615
1616 if (optlen != sizeof(u32))
1617 return -EINVAL;
1618 if (get_user(v, (u32 __user *)optval))
1619 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001620 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1621 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1622 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001623 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001624 return -EBUSY;
1625
1626 rtnl_lock();
1627 ret = 0;
1628 if (!ip6mr_new_table(net, v))
1629 ret = -ENOMEM;
1630 raw6_sk(sk)->ip6mr_table = v;
1631 rtnl_unlock();
1632 return ret;
1633 }
1634#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001635 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001636 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001637 * set.
1638 */
1639 default:
1640 return -ENOPROTOOPT;
1641 }
1642}
1643
1644/*
1645 * Getsock opt support for the multicast routing system.
1646 */
1647
1648int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1649 int __user *optlen)
1650{
1651 int olr;
1652 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001653 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001654 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001655
Xin Long99253eb2017-02-24 16:29:06 +08001656 if (sk->sk_type != SOCK_RAW ||
1657 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1658 return -EOPNOTSUPP;
1659
Patrick McHardyd1db2752010-05-11 14:40:55 +02001660 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001661 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001662 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001663
1664 switch (optname) {
1665 case MRT6_VERSION:
1666 val = 0x0305;
1667 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001668#ifdef CONFIG_IPV6_PIMSM_V2
1669 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001670 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001671 break;
1672#endif
1673 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001674 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001675 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001676 default:
1677 return -ENOPROTOOPT;
1678 }
1679
1680 if (get_user(olr, optlen))
1681 return -EFAULT;
1682
1683 olr = min_t(int, olr, sizeof(int));
1684 if (olr < 0)
1685 return -EINVAL;
1686
1687 if (put_user(olr, optlen))
1688 return -EFAULT;
1689 if (copy_to_user(optval, &val, olr))
1690 return -EFAULT;
1691 return 0;
1692}
1693
1694/*
1695 * The IP multicast ioctl support routines.
1696 */
1697
1698int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1699{
1700 struct sioc_sg_req6 sr;
1701 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001702 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001703 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001704 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001705 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001706
1707 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001708 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001709 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001710
1711 switch (cmd) {
1712 case SIOCGETMIFCNT_IN6:
1713 if (copy_from_user(&vr, arg, sizeof(vr)))
1714 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001715 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001716 return -EINVAL;
1717 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001718 vif = &mrt->vif_table[vr.mifi];
1719 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001720 vr.icount = vif->pkt_in;
1721 vr.ocount = vif->pkt_out;
1722 vr.ibytes = vif->bytes_in;
1723 vr.obytes = vif->bytes_out;
1724 read_unlock(&mrt_lock);
1725
1726 if (copy_to_user(arg, &vr, sizeof(vr)))
1727 return -EFAULT;
1728 return 0;
1729 }
1730 read_unlock(&mrt_lock);
1731 return -EADDRNOTAVAIL;
1732 case SIOCGETSGCNT_IN6:
1733 if (copy_from_user(&sr, arg, sizeof(sr)))
1734 return -EFAULT;
1735
Yuval Mintz87c418b2018-02-28 23:29:31 +02001736 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001737 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001738 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001739 sr.pktcnt = c->_c.mfc_un.res.pkt;
1740 sr.bytecnt = c->_c.mfc_un.res.bytes;
1741 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001742 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001743
1744 if (copy_to_user(arg, &sr, sizeof(sr)))
1745 return -EFAULT;
1746 return 0;
1747 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001748 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001749 return -EADDRNOTAVAIL;
1750 default:
1751 return -ENOIOCTLCMD;
1752 }
1753}
1754
David S. Millere2d57762011-02-03 17:59:32 -08001755#ifdef CONFIG_COMPAT
1756struct compat_sioc_sg_req6 {
1757 struct sockaddr_in6 src;
1758 struct sockaddr_in6 grp;
1759 compat_ulong_t pktcnt;
1760 compat_ulong_t bytecnt;
1761 compat_ulong_t wrong_if;
1762};
1763
1764struct compat_sioc_mif_req6 {
1765 mifi_t mifi;
1766 compat_ulong_t icount;
1767 compat_ulong_t ocount;
1768 compat_ulong_t ibytes;
1769 compat_ulong_t obytes;
1770};
1771
1772int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1773{
1774 struct compat_sioc_sg_req6 sr;
1775 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001776 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001777 struct mfc6_cache *c;
1778 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001779 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001780
1781 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001782 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001783 return -ENOENT;
1784
1785 switch (cmd) {
1786 case SIOCGETMIFCNT_IN6:
1787 if (copy_from_user(&vr, arg, sizeof(vr)))
1788 return -EFAULT;
1789 if (vr.mifi >= mrt->maxvif)
1790 return -EINVAL;
1791 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001792 vif = &mrt->vif_table[vr.mifi];
1793 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001794 vr.icount = vif->pkt_in;
1795 vr.ocount = vif->pkt_out;
1796 vr.ibytes = vif->bytes_in;
1797 vr.obytes = vif->bytes_out;
1798 read_unlock(&mrt_lock);
1799
1800 if (copy_to_user(arg, &vr, sizeof(vr)))
1801 return -EFAULT;
1802 return 0;
1803 }
1804 read_unlock(&mrt_lock);
1805 return -EADDRNOTAVAIL;
1806 case SIOCGETSGCNT_IN6:
1807 if (copy_from_user(&sr, arg, sizeof(sr)))
1808 return -EFAULT;
1809
Yuval Mintz87c418b2018-02-28 23:29:31 +02001810 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001811 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1812 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001813 sr.pktcnt = c->_c.mfc_un.res.pkt;
1814 sr.bytecnt = c->_c.mfc_un.res.bytes;
1815 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001816 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001817
1818 if (copy_to_user(arg, &sr, sizeof(sr)))
1819 return -EFAULT;
1820 return 0;
1821 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001822 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001823 return -EADDRNOTAVAIL;
1824 default:
1825 return -ENOIOCTLCMD;
1826 }
1827}
1828#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001829
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001830static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001831{
Eric Dumazet1d015502016-04-27 16:44:40 -07001832 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1833 IPSTATS_MIB_OUTFORWDATAGRAMS);
1834 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1835 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001836 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001837}
1838
1839/*
1840 * Processing handlers for ip6mr_forward
1841 */
1842
Yuval Mintzb70432f2018-02-28 23:29:32 +02001843static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001844 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001845{
1846 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001847 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001848 struct net_device *dev;
1849 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001850 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001851
Ian Morris63159f22015-03-29 14:00:04 +01001852 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001853 goto out_free;
1854
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001855#ifdef CONFIG_IPV6_PIMSM_V2
1856 if (vif->flags & MIFF_REGISTER) {
1857 vif->pkt_out++;
1858 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001859 vif->dev->stats.tx_bytes += skb->len;
1860 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001861 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001862 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001863 }
1864#endif
1865
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001866 ipv6h = ipv6_hdr(skb);
1867
David S. Miller4c9483b2011-03-12 16:22:43 -05001868 fl6 = (struct flowi6) {
1869 .flowi6_oif = vif->link,
1870 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001871 };
1872
David S. Miller4c9483b2011-03-12 16:22:43 -05001873 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001874 if (dst->error) {
1875 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001876 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00001877 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001878
Eric Dumazetadf30902009-06-02 05:19:30 +00001879 skb_dst_drop(skb);
1880 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001881
1882 /*
1883 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1884 * not only before forwarding, but after forwarding on all output
1885 * interfaces. It is clear, if mrouter runs a multicasting
1886 * program, it should receive packets not depending to what interface
1887 * program is joined.
1888 * If we will not make it, the program will have to join on all
1889 * interfaces. On the other hand, multihoming host (or router, but
1890 * not mrouter) cannot join to more than one interface - it will
1891 * result in receiving multiple packets.
1892 */
1893 dev = vif->dev;
1894 skb->dev = dev;
1895 vif->pkt_out++;
1896 vif->bytes_out += skb->len;
1897
1898 /* We are about to write */
1899 /* XXX: extension headers? */
1900 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
1901 goto out_free;
1902
1903 ipv6h = ipv6_hdr(skb);
1904 ipv6h->hop_limit--;
1905
1906 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
1907
Eric W. Biederman29a26a52015-09-15 20:04:16 -05001908 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
1909 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001910 ip6mr_forward2_finish);
1911
1912out_free:
1913 kfree_skb(skb);
1914 return 0;
1915}
1916
Yuval Mintzb70432f2018-02-28 23:29:32 +02001917static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001918{
1919 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001920
1921 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001922 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001923 break;
1924 }
1925 return ct;
1926}
1927
Yuval Mintzb70432f2018-02-28 23:29:32 +02001928static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +02001929 struct sk_buff *skb, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001930{
1931 int psend = -1;
1932 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001933 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001934
Yuval Mintz494fff52018-02-28 23:29:34 +02001935 vif = c->_c.mfc_parent;
1936 c->_c.mfc_un.res.pkt++;
1937 c->_c.mfc_un.res.bytes += skb->len;
1938 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001939
Yuval Mintz494fff52018-02-28 23:29:34 +02001940 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001941 struct mfc6_cache *cache_proxy;
1942
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01001943 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001944 * interface is part of the static tree.
1945 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02001946 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02001947 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001948 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02001949 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001950 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001951 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001952 }
1953 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001954 }
1955
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001956 /*
1957 * Wrong interface: drop packet and (maybe) send PIM assert.
1958 */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001959 if (mrt->vif_table[vif].dev != skb->dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001960 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001961
Patrick McHardy6bd52142010-05-11 14:40:53 +02001962 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001963 /* pimsm uses asserts, when switching from RPT to SPT,
1964 so that we cannot check that packet arrived on an oif.
1965 It is bad, but otherwise we would need to move pretty
1966 large chunk of pimd to kernel. Ough... --ANK
1967 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001968 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02001969 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001970 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02001971 c->_c.mfc_un.res.last_assert +
1972 MFC_ASSERT_THRESH)) {
1973 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001974 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001975 }
1976 goto dont_forward;
1977 }
1978
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001979forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02001980 mrt->vif_table[vif].pkt_in++;
1981 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001982
1983 /*
1984 * Forward the frame
1985 */
Yuval Mintz494fff52018-02-28 23:29:34 +02001986 if (ipv6_addr_any(&c->mf6c_origin) &&
1987 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001988 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02001989 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001990 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02001991 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001992 /* It's an (*,*) entry and the packet is not coming from
1993 * the upstream: forward the packet to the upstream
1994 * only.
1995 */
Yuval Mintz494fff52018-02-28 23:29:34 +02001996 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001997 goto last_forward;
1998 }
1999 goto dont_forward;
2000 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002001 for (ct = c->_c.mfc_un.res.maxvif - 1;
2002 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002003 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002004 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2005 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002006 if (psend != -1) {
2007 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2008 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002009 ip6mr_forward2(net, mrt, skb2,
2010 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002011 }
2012 psend = ct;
2013 }
2014 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002015last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002016 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002017 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002018 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002019 }
2020
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002021dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002022 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002023}
2024
2025
2026/*
2027 * Multicast packets for forwarding arrive here
2028 */
2029
2030int ip6_mr_input(struct sk_buff *skb)
2031{
2032 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002033 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002034 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002035 struct flowi6 fl6 = {
2036 .flowi6_iif = skb->dev->ifindex,
2037 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002038 };
2039 int err;
2040
David S. Miller4c9483b2011-03-12 16:22:43 -05002041 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002042 if (err < 0) {
2043 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002044 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002045 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002046
2047 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002048 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002049 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002050 if (!cache) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002051 int vif = ip6mr_find_vif(mrt, skb->dev);
2052
2053 if (vif >= 0)
2054 cache = ip6mr_cache_find_any(mrt,
2055 &ipv6_hdr(skb)->daddr,
2056 vif);
2057 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002058
2059 /*
2060 * No usable cache entry
2061 */
Ian Morris63159f22015-03-29 14:00:04 +01002062 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002063 int vif;
2064
Patrick McHardy6bd52142010-05-11 14:40:53 +02002065 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002066 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002067 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002068 read_unlock(&mrt_lock);
2069
2070 return err;
2071 }
2072 read_unlock(&mrt_lock);
2073 kfree_skb(skb);
2074 return -ENODEV;
2075 }
2076
Patrick McHardy6bd52142010-05-11 14:40:53 +02002077 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002078
2079 read_unlock(&mrt_lock);
2080
2081 return 0;
2082}
2083
2084
Yuval Mintzb70432f2018-02-28 23:29:32 +02002085static int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002086 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002087{
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002088 struct rta_mfc_stats mfcs;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002089 struct nlattr *mp_attr;
2090 struct rtnexthop *nhp;
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002091 unsigned long lastuse;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002092 int ct;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002093
Nicolas Dichtel74381892010-03-25 23:45:35 +00002094 /* If cache is unresolved, don't try to parse IIF and OIF */
Yuval Mintz494fff52018-02-28 23:29:34 +02002095 if (c->_c.mfc_parent >= MAXMIFS) {
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002096 rtm->rtm_flags |= RTNH_F_UNRESOLVED;
Nicolas Dichtel74381892010-03-25 23:45:35 +00002097 return -ENOENT;
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002098 }
Nicolas Dichtel74381892010-03-25 23:45:35 +00002099
Yuval Mintz494fff52018-02-28 23:29:34 +02002100 if (VIF_EXISTS(mrt, c->_c.mfc_parent) &&
Yuval Mintzb70432f2018-02-28 23:29:32 +02002101 nla_put_u32(skb, RTA_IIF,
Yuval Mintz494fff52018-02-28 23:29:34 +02002102 mrt->vif_table[c->_c.mfc_parent].dev->ifindex) < 0)
Thomas Graf74a0bd72012-06-26 23:36:14 +00002103 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002104 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
Ian Morris63159f22015-03-29 14:00:04 +01002105 if (!mp_attr)
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002106 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002107
Yuval Mintz494fff52018-02-28 23:29:34 +02002108 for (ct = c->_c.mfc_un.res.minvif;
2109 ct < c->_c.mfc_un.res.maxvif; ct++) {
2110 if (VIF_EXISTS(mrt, ct) && c->_c.mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002111 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
Ian Morris63159f22015-03-29 14:00:04 +01002112 if (!nhp) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002113 nla_nest_cancel(skb, mp_attr);
2114 return -EMSGSIZE;
2115 }
2116
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002117 nhp->rtnh_flags = 0;
Yuval Mintz494fff52018-02-28 23:29:34 +02002118 nhp->rtnh_hops = c->_c.mfc_un.res.ttls[ct];
Yuval Mintzb70432f2018-02-28 23:29:32 +02002119 nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002120 nhp->rtnh_len = sizeof(*nhp);
2121 }
2122 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002123
2124 nla_nest_end(skb, mp_attr);
2125
Yuval Mintz494fff52018-02-28 23:29:34 +02002126 lastuse = READ_ONCE(c->_c.mfc_un.res.lastuse);
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002127 lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
2128
Yuval Mintz494fff52018-02-28 23:29:34 +02002129 mfcs.mfcs_packets = c->_c.mfc_un.res.pkt;
2130 mfcs.mfcs_bytes = c->_c.mfc_un.res.bytes;
2131 mfcs.mfcs_wrong_if = c->_c.mfc_un.res.wrong_if;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002132 if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002133 nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002134 RTA_PAD))
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002135 return -EMSGSIZE;
2136
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002137 rtm->rtm_type = RTN_MULTICAST;
2138 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002139}
2140
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002141int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002142 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002143{
2144 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002145 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002146 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002147 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002148
Patrick McHardyd1db2752010-05-11 14:40:55 +02002149 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002150 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002151 return -ENOENT;
2152
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002153 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002154 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002155 if (!cache && skb->dev) {
2156 int vif = ip6mr_find_vif(mrt, skb->dev);
2157
2158 if (vif >= 0)
2159 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2160 vif);
2161 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002162
2163 if (!cache) {
2164 struct sk_buff *skb2;
2165 struct ipv6hdr *iph;
2166 struct net_device *dev;
2167 int vif;
2168
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002169 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002170 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002171 read_unlock(&mrt_lock);
2172 return -ENODEV;
2173 }
2174
2175 /* really correct? */
2176 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2177 if (!skb2) {
2178 read_unlock(&mrt_lock);
2179 return -ENOMEM;
2180 }
2181
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002182 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002183 skb_reset_transport_header(skb2);
2184
2185 skb_put(skb2, sizeof(struct ipv6hdr));
2186 skb_reset_network_header(skb2);
2187
2188 iph = ipv6_hdr(skb2);
2189 iph->version = 0;
2190 iph->priority = 0;
2191 iph->flow_lbl[0] = 0;
2192 iph->flow_lbl[1] = 0;
2193 iph->flow_lbl[2] = 0;
2194 iph->payload_len = 0;
2195 iph->nexthdr = IPPROTO_NONE;
2196 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002197 iph->saddr = rt->rt6i_src.addr;
2198 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002199
Patrick McHardy6bd52142010-05-11 14:40:53 +02002200 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002201 read_unlock(&mrt_lock);
2202
2203 return err;
2204 }
2205
David Ahernfd61c6b2017-01-17 15:51:07 -08002206 if (rtm->rtm_flags & RTM_F_NOTIFY)
Yuval Mintz494fff52018-02-28 23:29:34 +02002207 cache->_c.mfc_flags |= MFC_NOTIFY;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002208
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002209 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002210 read_unlock(&mrt_lock);
2211 return err;
2212}
2213
Yuval Mintzb70432f2018-02-28 23:29:32 +02002214static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002215 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2216 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002217{
2218 struct nlmsghdr *nlh;
2219 struct rtmsg *rtm;
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002220 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002221
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002222 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002223 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002224 return -EMSGSIZE;
2225
2226 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002227 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002228 rtm->rtm_dst_len = 128;
2229 rtm->rtm_src_len = 128;
2230 rtm->rtm_tos = 0;
2231 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002232 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2233 goto nla_put_failure;
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002234 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002235 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002236 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002237 rtm->rtm_protocol = RTPROT_STATIC;
2238 else
2239 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002240 rtm->rtm_flags = 0;
2241
Jiri Benc930345e2015-03-29 16:59:25 +02002242 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2243 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002244 goto nla_put_failure;
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002245 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2246 /* do not break the dump if cache is unresolved */
2247 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002248 goto nla_put_failure;
2249
Johannes Berg053c0952015-01-16 22:09:00 +01002250 nlmsg_end(skb, nlh);
2251 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002252
2253nla_put_failure:
2254 nlmsg_cancel(skb, nlh);
2255 return -EMSGSIZE;
2256}
2257
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002258static int mr6_msgsize(bool unresolved, int maxvif)
2259{
2260 size_t len =
2261 NLMSG_ALIGN(sizeof(struct rtmsg))
2262 + nla_total_size(4) /* RTA_TABLE */
2263 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2264 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2265 ;
2266
2267 if (!unresolved)
2268 len = len
2269 + nla_total_size(4) /* RTA_IIF */
2270 + nla_total_size(0) /* RTA_MULTIPATH */
2271 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2272 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002273 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002274 ;
2275
2276 return len;
2277}
2278
Yuval Mintzb70432f2018-02-28 23:29:32 +02002279static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002280 int cmd)
2281{
2282 struct net *net = read_pnet(&mrt->net);
2283 struct sk_buff *skb;
2284 int err = -ENOBUFS;
2285
Yuval Mintz494fff52018-02-28 23:29:34 +02002286 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002287 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002288 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002289 goto errout;
2290
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002291 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002292 if (err < 0)
2293 goto errout;
2294
2295 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2296 return;
2297
2298errout:
2299 kfree_skb(skb);
2300 if (err < 0)
2301 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2302}
2303
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002304static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2305{
2306 size_t len =
2307 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2308 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2309 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2310 /* IP6MRA_CREPORT_SRC_ADDR */
2311 + nla_total_size(sizeof(struct in6_addr))
2312 /* IP6MRA_CREPORT_DST_ADDR */
2313 + nla_total_size(sizeof(struct in6_addr))
2314 /* IP6MRA_CREPORT_PKT */
2315 + nla_total_size(payloadlen)
2316 ;
2317
2318 return len;
2319}
2320
Yuval Mintzb70432f2018-02-28 23:29:32 +02002321static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002322{
2323 struct net *net = read_pnet(&mrt->net);
2324 struct nlmsghdr *nlh;
2325 struct rtgenmsg *rtgenm;
2326 struct mrt6msg *msg;
2327 struct sk_buff *skb;
2328 struct nlattr *nla;
2329 int payloadlen;
2330
2331 payloadlen = pkt->len - sizeof(struct mrt6msg);
2332 msg = (struct mrt6msg *)skb_transport_header(pkt);
2333
2334 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2335 if (!skb)
2336 goto errout;
2337
2338 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2339 sizeof(struct rtgenmsg), 0);
2340 if (!nlh)
2341 goto errout;
2342 rtgenm = nlmsg_data(nlh);
2343 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2344 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2345 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2346 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2347 &msg->im6_src) ||
2348 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2349 &msg->im6_dst))
2350 goto nla_put_failure;
2351
2352 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2353 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2354 nla_data(nla), payloadlen))
2355 goto nla_put_failure;
2356
2357 nlmsg_end(skb, nlh);
2358
2359 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2360 return;
2361
2362nla_put_failure:
2363 nlmsg_cancel(skb, nlh);
2364errout:
2365 kfree_skb(skb);
2366 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2367}
2368
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002369static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2370{
2371 struct net *net = sock_net(skb->sk);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002372 unsigned int t = 0, s_t;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002373 unsigned int e = 0, s_e;
Yuval Mintz494fff52018-02-28 23:29:34 +02002374 struct mr_table *mrt;
2375 struct mr_mfc *mfc;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002376
2377 s_t = cb->args[0];
Yuval Mintz87c418b2018-02-28 23:29:31 +02002378 s_e = cb->args[1];
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002379
Yuval Mintz87c418b2018-02-28 23:29:31 +02002380 rcu_read_lock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002381 ip6mr_for_each_table(mrt, net) {
2382 if (t < s_t)
2383 goto next_table;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002384 list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002385 if (e < s_e)
2386 goto next_entry;
2387 if (ip6mr_fill_mroute(mrt, skb,
2388 NETLINK_CB(cb->skb).portid,
2389 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002390 (struct mfc6_cache *)mfc,
2391 RTM_NEWROUTE, NLM_F_MULTI) < 0)
Yuval Mintz87c418b2018-02-28 23:29:31 +02002392 goto done;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002393next_entry:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002394 e++;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002395 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02002396 e = 0;
2397 s_e = 0;
2398
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002399 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002400 list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002401 if (e < s_e)
2402 goto next_entry2;
2403 if (ip6mr_fill_mroute(mrt, skb,
2404 NETLINK_CB(cb->skb).portid,
2405 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002406 (struct mfc6_cache *)mfc,
2407 RTM_NEWROUTE, NLM_F_MULTI) < 0) {
Nicolas Dichtel1eb99af52012-12-04 01:13:39 +00002408 spin_unlock_bh(&mfc_unres_lock);
2409 goto done;
2410 }
2411next_entry2:
2412 e++;
2413 }
2414 spin_unlock_bh(&mfc_unres_lock);
2415 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002416next_table:
2417 t++;
2418 }
2419done:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002420 rcu_read_unlock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002421
Yuval Mintz87c418b2018-02-28 23:29:31 +02002422 cb->args[1] = e;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002423 cb->args[0] = t;
2424
2425 return skb->len;
2426}