blob: 26315065e7df53f5ca160244f54fb7a8f8a1a579 [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
340struct ipmr_vif_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800341 struct seq_net_private p;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200342 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900343 int ct;
344};
345
Yuval Mintz6853f212018-02-28 23:29:29 +0200346static struct vif_device *ip6mr_vif_seq_idx(struct net *net,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800347 struct ipmr_vif_iter *iter,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900348 loff_t pos)
349{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200350 struct mr_table *mrt = iter->mrt;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200351
352 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200353 if (!VIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900354 continue;
355 if (pos-- == 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200356 return &mrt->vif_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900357 }
358 return NULL;
359}
360
361static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
362 __acquires(mrt_lock)
363{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200364 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800365 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200366 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200367
368 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100369 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200370 return ERR_PTR(-ENOENT);
371
372 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800373
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900374 read_lock(&mrt_lock);
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800375 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
376 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900377}
378
379static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
380{
381 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800382 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200383 struct mr_table *mrt = iter->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900384
385 ++*pos;
386 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800387 return ip6mr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900388
Patrick McHardy6bd52142010-05-11 14:40:53 +0200389 while (++iter->ct < mrt->maxvif) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200390 if (!VIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900391 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200392 return &mrt->vif_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900393 }
394 return NULL;
395}
396
397static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
398 __releases(mrt_lock)
399{
400 read_unlock(&mrt_lock);
401}
402
403static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
404{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200405 struct ipmr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200406 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800407
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900408 if (v == SEQ_START_TOKEN) {
409 seq_puts(seq,
410 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
411 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200412 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900413 const char *name = vif->dev ? vif->dev->name : "none";
414
415 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100416 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200417 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900418 name, vif->bytes_in, vif->pkt_in,
419 vif->bytes_out, vif->pkt_out,
420 vif->flags);
421 }
422 return 0;
423}
424
Stephen Hemminger98147d52009-09-01 19:25:02 +0000425static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900426 .start = ip6mr_vif_seq_start,
427 .next = ip6mr_vif_seq_next,
428 .stop = ip6mr_vif_seq_stop,
429 .show = ip6mr_vif_seq_show,
430};
431
432static int ip6mr_vif_open(struct inode *inode, struct file *file)
433{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800434 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
435 sizeof(struct ipmr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900436}
437
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000438static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900439 .open = ip6mr_vif_open,
440 .read = seq_read,
441 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800442 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900443};
444
445static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
446{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800447 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200448 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800449
Patrick McHardyd1db2752010-05-11 14:40:55 +0200450 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100451 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200452 return ERR_PTR(-ENOENT);
453
Yuval Mintzc8d61962018-02-28 23:29:36 +0200454 return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900455}
456
457static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
458{
459 int n;
460
461 if (v == SEQ_START_TOKEN) {
462 seq_puts(seq,
463 "Group "
464 "Origin "
465 "Iif Pkts Bytes Wrong Oifs\n");
466 } else {
467 const struct mfc6_cache *mfc = v;
Yuval Mintzc8d61962018-02-28 23:29:36 +0200468 const struct mr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200469 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900470
Benjamin Thery999890b2008-12-03 22:22:16 -0800471 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700472 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200473 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900474
Yuval Mintzb70432f2018-02-28 23:29:32 +0200475 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800476 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200477 mfc->_c.mfc_un.res.pkt,
478 mfc->_c.mfc_un.res.bytes,
479 mfc->_c.mfc_un.res.wrong_if);
480 for (n = mfc->_c.mfc_un.res.minvif;
481 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200482 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200483 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900484 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200485 " %2d:%-3d", n,
486 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900487 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800488 } else {
489 /* unresolved mfc_caches don't contain
490 * pkt, bytes and wrong_if values
491 */
492 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900493 }
494 seq_putc(seq, '\n');
495 }
496 return 0;
497}
498
James Morris88e9d342009-09-22 16:43:43 -0700499static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900500 .start = ipmr_mfc_seq_start,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200501 .next = mr_mfc_seq_next,
502 .stop = mr_mfc_seq_stop,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900503 .show = ipmr_mfc_seq_show,
504};
505
506static int ipmr_mfc_open(struct inode *inode, struct file *file)
507{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800508 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
Yuval Mintzc8d61962018-02-28 23:29:36 +0200509 sizeof(struct mr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900510}
511
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000512static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900513 .open = ipmr_mfc_open,
514 .read = seq_read,
515 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800516 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900517};
518#endif
519
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900520#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900521
522static int pim6_rcv(struct sk_buff *skb)
523{
524 struct pimreghdr *pim;
525 struct ipv6hdr *encap;
526 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800527 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200528 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500529 struct flowi6 fl6 = {
530 .flowi6_iif = skb->dev->ifindex,
531 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200532 };
533 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900534
535 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
536 goto drop;
537
538 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100539 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900540 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800541 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
542 sizeof(*pim), IPPROTO_PIM,
543 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700544 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900545 goto drop;
546
547 /* check if the inner packet is destined to mcast group */
548 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
549 sizeof(*pim));
550
551 if (!ipv6_addr_is_multicast(&encap->daddr) ||
552 encap->payload_len == 0 ||
553 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
554 goto drop;
555
David S. Miller4c9483b2011-03-12 16:22:43 -0500556 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200557 goto drop;
558 reg_vif_num = mrt->mroute_reg_vif_num;
559
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900560 read_lock(&mrt_lock);
561 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200562 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900563 if (reg_dev)
564 dev_hold(reg_dev);
565 read_unlock(&mrt_lock);
566
Ian Morris63159f22015-03-29 14:00:04 +0100567 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900568 goto drop;
569
570 skb->mac_header = skb->network_header;
571 skb_pull(skb, (u8 *)encap - skb->data);
572 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800573 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000574 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700575
Nicolas Dichtelea231922013-09-02 15:34:58 +0200576 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700577
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000578 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000579
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900580 dev_put(reg_dev);
581 return 0;
582 drop:
583 kfree_skb(skb);
584 return 0;
585}
586
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000587static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900588 .handler = pim6_rcv,
589};
590
591/* Service routines creating virtual interfaces: PIMREG */
592
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000593static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
594 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900595{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800596 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200597 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500598 struct flowi6 fl6 = {
599 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700600 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500601 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200602 };
603 int err;
604
David S. Miller4c9483b2011-03-12 16:22:43 -0500605 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000606 if (err < 0) {
607 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200608 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000609 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800610
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900611 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700612 dev->stats.tx_bytes += skb->len;
613 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200614 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900615 read_unlock(&mrt_lock);
616 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000617 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900618}
619
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200620static int reg_vif_get_iflink(const struct net_device *dev)
621{
622 return 0;
623}
624
Stephen Hemminger007c3832008-11-20 20:28:35 -0800625static const struct net_device_ops reg_vif_netdev_ops = {
626 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200627 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800628};
629
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900630static void reg_vif_setup(struct net_device *dev)
631{
632 dev->type = ARPHRD_PIMREG;
633 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
634 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800635 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400636 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700637 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900638}
639
Yuval Mintzb70432f2018-02-28 23:29:32 +0200640static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900641{
642 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200643 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900644
Patrick McHardyd1db2752010-05-11 14:40:55 +0200645 if (mrt->id == RT6_TABLE_DFLT)
646 sprintf(name, "pim6reg");
647 else
648 sprintf(name, "pim6reg%u", mrt->id);
649
Tom Gundersenc835a672014-07-14 16:37:24 +0200650 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100651 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900652 return NULL;
653
Benjamin Thery8229efd2008-12-10 16:30:15 -0800654 dev_net_set(dev, net);
655
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900656 if (register_netdevice(dev)) {
657 free_netdev(dev);
658 return NULL;
659 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900660
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900661 if (dev_open(dev))
662 goto failure;
663
Wang Chen7af3db72008-07-14 20:54:54 -0700664 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900665 return dev;
666
667failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900668 unregister_netdevice(dev);
669 return NULL;
670}
671#endif
672
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900673/*
674 * Delete a VIF entry
675 */
676
Yuval Mintzb70432f2018-02-28 23:29:32 +0200677static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300678 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900679{
Yuval Mintz6853f212018-02-28 23:29:29 +0200680 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900681 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800682 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200683
684 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900685 return -EADDRNOTAVAIL;
686
Yuval Mintzb70432f2018-02-28 23:29:32 +0200687 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900688
689 write_lock_bh(&mrt_lock);
690 dev = v->dev;
691 v->dev = NULL;
692
693 if (!dev) {
694 write_unlock_bh(&mrt_lock);
695 return -EADDRNOTAVAIL;
696 }
697
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900698#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200699 if (vifi == mrt->mroute_reg_vif_num)
700 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900701#endif
702
Patrick McHardy6bd52142010-05-11 14:40:53 +0200703 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900704 int tmp;
705 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200706 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900707 break;
708 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200709 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900710 }
711
712 write_unlock_bh(&mrt_lock);
713
714 dev_set_allmulti(dev, -1);
715
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800716 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000717 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800718 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700719 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000720 NETCONFA_MC_FORWARDING,
721 dev->ifindex, &in6_dev->cnf);
722 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800723
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300724 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000725 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900726
727 dev_put(dev);
728 return 0;
729}
730
Yuval Mintz87c418b2018-02-28 23:29:31 +0200731static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
732{
Yuval Mintz494fff52018-02-28 23:29:34 +0200733 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200734
Yuval Mintz494fff52018-02-28 23:29:34 +0200735 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200736}
737
Benjamin Thery58701ad2008-12-10 16:22:34 -0800738static inline void ip6mr_cache_free(struct mfc6_cache *c)
739{
Yuval Mintz494fff52018-02-28 23:29:34 +0200740 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800741}
742
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900743/* Destroy an unresolved cache entry, killing queued skbs
744 and reporting error to netlink readers.
745 */
746
Yuval Mintzb70432f2018-02-28 23:29:32 +0200747static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900748{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200749 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900750 struct sk_buff *skb;
751
Patrick McHardy6bd52142010-05-11 14:40:53 +0200752 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900753
Yuval Mintz494fff52018-02-28 23:29:34 +0200754 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900755 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200756 struct nlmsghdr *nlh = skb_pull(skb,
757 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900758 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000759 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900760 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000761 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000762 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900763 } else
764 kfree_skb(skb);
765 }
766
Benjamin Thery58701ad2008-12-10 16:22:34 -0800767 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900768}
769
770
Patrick McHardyc476efb2010-05-11 14:40:48 +0200771/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900772
Yuval Mintzb70432f2018-02-28 23:29:32 +0200773static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900774{
775 unsigned long now = jiffies;
776 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200777 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900778
Yuval Mintzb70432f2018-02-28 23:29:32 +0200779 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900780 if (time_after(c->mfc_un.unres.expires, now)) {
781 /* not yet... */
782 unsigned long interval = c->mfc_un.unres.expires - now;
783 if (interval < expires)
784 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900785 continue;
786 }
787
Patrick McHardyf30a77842010-05-11 14:40:51 +0200788 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200789 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
790 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900791 }
792
Yuval Mintzb70432f2018-02-28 23:29:32 +0200793 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200794 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900795}
796
Kees Cooke99e88a2017-10-16 14:43:17 -0700797static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900798{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200799 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200800
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900801 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200802 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900803 return;
804 }
805
Yuval Mintzb70432f2018-02-28 23:29:32 +0200806 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200807 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900808
809 spin_unlock(&mfc_unres_lock);
810}
811
812/* Fill oifs list. It is called under write locked mrt_lock. */
813
Yuval Mintzb70432f2018-02-28 23:29:32 +0200814static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200815 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200816 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900817{
818 int vifi;
819
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300820 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900821 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300822 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900823
Patrick McHardy6bd52142010-05-11 14:40:53 +0200824 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200825 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800826 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900827 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
828 if (cache->mfc_un.res.minvif > vifi)
829 cache->mfc_un.res.minvif = vifi;
830 if (cache->mfc_un.res.maxvif <= vifi)
831 cache->mfc_un.res.maxvif = vifi + 1;
832 }
833 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200834 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900835}
836
Yuval Mintzb70432f2018-02-28 23:29:32 +0200837static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200838 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900839{
840 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200841 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900842 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800843 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700844 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900845
846 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200847 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900848 return -EADDRINUSE;
849
850 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900851#ifdef CONFIG_IPV6_PIMSM_V2
852 case MIFF_REGISTER:
853 /*
854 * Special Purpose VIF in PIM
855 * All the packets will be sent to the daemon
856 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200857 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900858 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200859 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900860 if (!dev)
861 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700862 err = dev_set_allmulti(dev, 1);
863 if (err) {
864 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700865 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700866 return err;
867 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900868 break;
869#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900870 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800871 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900872 if (!dev)
873 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700874 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700875 if (err) {
876 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700877 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700878 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900879 break;
880 default:
881 return -EINVAL;
882 }
883
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800884 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000885 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800886 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700887 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000888 NETCONFA_MC_FORWARDING,
889 dev->ifindex, &in6_dev->cnf);
890 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800891
Yuval Mintz6853f212018-02-28 23:29:29 +0200892 /* Fill in the VIF structures */
893 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
894 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
895 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900896
897 /* And finish update writing critical data */
898 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900899 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900900#ifdef CONFIG_IPV6_PIMSM_V2
901 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200902 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900903#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200904 if (vifi + 1 > mrt->maxvif)
905 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900906 write_unlock_bh(&mrt_lock);
907 return 0;
908}
909
Yuval Mintzb70432f2018-02-28 23:29:32 +0200910static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000911 const struct in6_addr *origin,
912 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900913{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200914 struct mfc6_cache_cmp_arg arg = {
915 .mf6c_origin = *origin,
916 .mf6c_mcastgrp = *mcastgrp,
917 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900918
Yuval Mintz845c9a72018-02-28 23:29:35 +0200919 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000920}
921
922/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200923static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000924 struct in6_addr *mcastgrp,
925 mifi_t mifi)
926{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200927 struct mfc6_cache_cmp_arg arg = {
928 .mf6c_origin = in6addr_any,
929 .mf6c_mcastgrp = *mcastgrp,
930 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000931
932 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +0200933 return mr_mfc_find_any_parent(mrt, mifi);
934 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +0000935}
936
Yuval Mintz87c418b2018-02-28 23:29:31 +0200937/* Look for a (S,G,iif) entry if parent != -1 */
938static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +0200939ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +0200940 const struct in6_addr *origin,
941 const struct in6_addr *mcastgrp,
942 int parent)
943{
944 struct mfc6_cache_cmp_arg arg = {
945 .mf6c_origin = *origin,
946 .mf6c_mcastgrp = *mcastgrp,
947 };
Yuval Mintz87c418b2018-02-28 23:29:31 +0200948
Yuval Mintz845c9a72018-02-28 23:29:35 +0200949 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200950}
951
Yuval Mintz845c9a72018-02-28 23:29:35 +0200952/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200953static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900954{
Joe Perches36cbac52008-12-03 22:27:25 -0800955 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +0100956 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900957 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200958 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
959 c->_c.mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900960 return c;
961}
962
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200963static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900964{
Joe Perches36cbac52008-12-03 22:27:25 -0800965 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +0100966 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900967 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +0200968 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
969 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900970 return c;
971}
972
973/*
974 * A cache entry has gone into a resolved state from queued
975 */
976
Yuval Mintzb70432f2018-02-28 23:29:32 +0200977static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200978 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900979{
980 struct sk_buff *skb;
981
982 /*
983 * Play the pending entries through our router
984 */
985
Yuval Mintz494fff52018-02-28 23:29:34 +0200986 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900987 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200988 struct nlmsghdr *nlh = skb_pull(skb,
989 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900990
Hong zhi guo573ce262013-03-27 06:47:04 +0000991 if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +0900992 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900993 } else {
994 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000995 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900996 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000997 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900998 }
Eric W. Biederman15e47302012-09-07 20:12:54 +0000999 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001000 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001001 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001002 }
1003}
1004
1005/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001006 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001007 *
1008 * Called under mrt_lock.
1009 */
1010
Yuval Mintzb70432f2018-02-28 23:29:32 +02001011static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001012 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001013{
Yuval Mintz8571ab42018-02-28 23:29:30 +02001014 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001015 struct sk_buff *skb;
1016 struct mrt6msg *msg;
1017 int ret;
1018
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001019#ifdef CONFIG_IPV6_PIMSM_V2
1020 if (assert == MRT6MSG_WHOLEPKT)
1021 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1022 +sizeof(*msg));
1023 else
1024#endif
1025 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001026
1027 if (!skb)
1028 return -ENOBUFS;
1029
1030 /* I suppose that internal messages
1031 * do not require checksums */
1032
1033 skb->ip_summed = CHECKSUM_UNNECESSARY;
1034
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001035#ifdef CONFIG_IPV6_PIMSM_V2
1036 if (assert == MRT6MSG_WHOLEPKT) {
1037 /* Ugly, but we have no choice with this interface.
1038 Duplicate old header, fix length etc.
1039 And all this only to mangle msg->im6_msgtype and
1040 to set msg->im6_mbz to "mbz" :-)
1041 */
1042 skb_push(skb, -skb_network_offset(pkt));
1043
1044 skb_push(skb, sizeof(*msg));
1045 skb_reset_transport_header(skb);
1046 msg = (struct mrt6msg *)skb_transport_header(skb);
1047 msg->im6_mbz = 0;
1048 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001049 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001050 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001051 msg->im6_src = ipv6_hdr(pkt)->saddr;
1052 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001053
1054 skb->ip_summed = CHECKSUM_UNNECESSARY;
1055 } else
1056#endif
1057 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001058 /*
1059 * Copy the IP header
1060 */
1061
1062 skb_put(skb, sizeof(struct ipv6hdr));
1063 skb_reset_network_header(skb);
1064 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1065
1066 /*
1067 * Add our header
1068 */
1069 skb_put(skb, sizeof(*msg));
1070 skb_reset_transport_header(skb);
1071 msg = (struct mrt6msg *)skb_transport_header(skb);
1072
1073 msg->im6_mbz = 0;
1074 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001075 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001076 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001077 msg->im6_src = ipv6_hdr(pkt)->saddr;
1078 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001079
Eric Dumazetadf30902009-06-02 05:19:30 +00001080 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001081 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001082 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001083
Yuval Mintz8571ab42018-02-28 23:29:30 +02001084 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001085 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001086 if (!mroute6_sk) {
1087 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001088 kfree_skb(skb);
1089 return -EINVAL;
1090 }
1091
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001092 mrt6msg_netlink_event(mrt, skb);
1093
Yuval Mintz8571ab42018-02-28 23:29:30 +02001094 /* Deliver to user space multicast routing algorithms */
1095 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1096 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001097 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001098 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001099 kfree_skb(skb);
1100 }
1101
1102 return ret;
1103}
1104
Yuval Mintz494fff52018-02-28 23:29:34 +02001105/* Queue a packet for resolution. It gets locked cache entry! */
1106static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
1107 struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001108{
Yuval Mintz494fff52018-02-28 23:29:34 +02001109 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001110 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001111 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001112
1113 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001114 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001115 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001116 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1117 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001118 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001119 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001120 }
1121
Patrick McHardyf30a77842010-05-11 14:40:51 +02001122 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001123 /*
1124 * Create a new entry if allowable
1125 */
1126
Patrick McHardy6bd52142010-05-11 14:40:53 +02001127 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001128 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001129 spin_unlock_bh(&mfc_unres_lock);
1130
1131 kfree_skb(skb);
1132 return -ENOBUFS;
1133 }
1134
Yuval Mintz494fff52018-02-28 23:29:34 +02001135 /* Fill in the new cache entry */
1136 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001137 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1138 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1139
1140 /*
1141 * Reflect first query at pim6sd
1142 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001143 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001144 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001145 /* If the report failed throw the cache entry
1146 out - Brad Parker
1147 */
1148 spin_unlock_bh(&mfc_unres_lock);
1149
Benjamin Thery58701ad2008-12-10 16:22:34 -08001150 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001151 kfree_skb(skb);
1152 return err;
1153 }
1154
Patrick McHardy6bd52142010-05-11 14:40:53 +02001155 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001156 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001157 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001158
Patrick McHardy6bd52142010-05-11 14:40:53 +02001159 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001160 }
1161
Yuval Mintz494fff52018-02-28 23:29:34 +02001162 /* See if we can append the packet */
1163 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001164 kfree_skb(skb);
1165 err = -ENOBUFS;
1166 } else {
Yuval Mintz494fff52018-02-28 23:29:34 +02001167 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001168 err = 0;
1169 }
1170
1171 spin_unlock_bh(&mfc_unres_lock);
1172 return err;
1173}
1174
1175/*
1176 * MFC6 cache manipulation by user space
1177 */
1178
Yuval Mintzb70432f2018-02-28 23:29:32 +02001179static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001180 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001181{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001182 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001183
Yuval Mintz87c418b2018-02-28 23:29:31 +02001184 /* The entries are added/deleted only under RTNL */
1185 rcu_read_lock();
1186 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1187 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1188 rcu_read_unlock();
1189 if (!c)
1190 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001191 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1192 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001193
Yuval Mintz87c418b2018-02-28 23:29:31 +02001194 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1195 ip6mr_cache_free(c);
1196 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001197}
1198
1199static int ip6mr_device_event(struct notifier_block *this,
1200 unsigned long event, void *ptr)
1201{
Jiri Pirko351638e2013-05-28 01:30:21 +00001202 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001203 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001204 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001205 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001206 int ct;
1207
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001208 if (event != NETDEV_UNREGISTER)
1209 return NOTIFY_DONE;
1210
Patrick McHardyd1db2752010-05-11 14:40:55 +02001211 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001212 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001213 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1214 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001215 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001216 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001217 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001218
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001219 return NOTIFY_DONE;
1220}
1221
1222static struct notifier_block ip6_mr_notifier = {
1223 .notifier_call = ip6mr_device_event
1224};
1225
1226/*
1227 * Setup for IP multicast routing
1228 */
1229
Benjamin Thery4e168802008-12-10 16:15:08 -08001230static int __net_init ip6mr_net_init(struct net *net)
1231{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001232 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001233
Patrick McHardyd1db2752010-05-11 14:40:55 +02001234 err = ip6mr_rules_init(net);
1235 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001236 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001237
1238#ifdef CONFIG_PROC_FS
1239 err = -ENOMEM;
Gao fengd4beaa62013-02-18 01:34:54 +00001240 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001241 goto proc_vif_fail;
Gao fengd4beaa62013-02-18 01:34:54 +00001242 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001243 goto proc_cache_fail;
1244#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001245
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001246 return 0;
1247
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001248#ifdef CONFIG_PROC_FS
1249proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001250 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001251proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001252 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001253#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001254fail:
1255 return err;
1256}
1257
1258static void __net_exit ip6mr_net_exit(struct net *net)
1259{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001260#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001261 remove_proc_entry("ip6_mr_cache", net->proc_net);
1262 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001263#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001264 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001265}
1266
1267static struct pernet_operations ip6mr_net_ops = {
1268 .init = ip6mr_net_init,
1269 .exit = ip6mr_net_exit,
Kirill Tkhaib01a59a2018-02-19 11:48:37 +03001270 .async = true,
Benjamin Thery4e168802008-12-10 16:15:08 -08001271};
1272
Wang Chen623d1a12008-07-03 12:13:30 +08001273int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001274{
Wang Chen623d1a12008-07-03 12:13:30 +08001275 int err;
1276
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001277 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1278 sizeof(struct mfc6_cache),
1279 0, SLAB_HWCACHE_ALIGN,
1280 NULL);
1281 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001282 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001283
Benjamin Thery4e168802008-12-10 16:15:08 -08001284 err = register_pernet_subsys(&ip6mr_net_ops);
1285 if (err)
1286 goto reg_pernet_fail;
1287
Wang Chen623d1a12008-07-03 12:13:30 +08001288 err = register_netdevice_notifier(&ip6_mr_notifier);
1289 if (err)
1290 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001291#ifdef CONFIG_IPV6_PIMSM_V2
1292 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001293 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001294 err = -EAGAIN;
1295 goto add_proto_fail;
1296 }
1297#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001298 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1299 NULL, ip6mr_rtm_dumproute, 0);
1300 if (err == 0)
1301 return 0;
1302
Tom Goff403dbb92009-06-14 03:16:13 -07001303#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001304 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001305add_proto_fail:
1306 unregister_netdevice_notifier(&ip6_mr_notifier);
1307#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001308reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001309 unregister_pernet_subsys(&ip6mr_net_ops);
1310reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001311 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001312 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001313}
1314
Wang Chen623d1a12008-07-03 12:13:30 +08001315void ip6_mr_cleanup(void)
1316{
Duan Jiongffb13882014-11-19 09:35:39 +08001317 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1318#ifdef CONFIG_IPV6_PIMSM_V2
1319 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1320#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001321 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001322 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001323 kmem_cache_destroy(mrt_cachep);
1324}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001325
Yuval Mintzb70432f2018-02-28 23:29:32 +02001326static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001327 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001328{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001329 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001330 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001331 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001332 bool found;
1333 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001334
Patrick McHardya50436f22010-03-17 06:04:14 +00001335 if (mfc->mf6cc_parent >= MAXMIFS)
1336 return -ENFILE;
1337
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001338 memset(ttls, 255, MAXMIFS);
1339 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001340 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1341 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001342 }
1343
Yuval Mintz87c418b2018-02-28 23:29:31 +02001344 /* The entries are added/deleted only under RTNL */
1345 rcu_read_lock();
1346 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1347 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1348 rcu_read_unlock();
1349 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001350 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001351 c->_c.mfc_parent = mfc->mf6cc_parent;
1352 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001353 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001354 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001355 write_unlock_bh(&mrt_lock);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001356 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001357 return 0;
1358 }
1359
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001360 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1361 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001362 return -EINVAL;
1363
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001364 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001365 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001366 return -ENOMEM;
1367
1368 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1369 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001370 c->_c.mfc_parent = mfc->mf6cc_parent;
1371 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001372 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001373 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001374
Yuval Mintz494fff52018-02-28 23:29:34 +02001375 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001376 ip6mr_rht_params);
1377 if (err) {
1378 pr_err("ip6mr: rhtable insert error %d\n", err);
1379 ip6mr_cache_free(c);
1380 return err;
1381 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001382 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001383
Yuval Mintz87c418b2018-02-28 23:29:31 +02001384 /* Check to see if we resolved a queued list. If so we
1385 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001386 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001387 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001388 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001389 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1390 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001391 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001392 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001393 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001394 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001395 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001396 break;
1397 }
1398 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001399 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001400 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001401 spin_unlock_bh(&mfc_unres_lock);
1402
Patrick McHardyf30a77842010-05-11 14:40:51 +02001403 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001404 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001405 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001406 }
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001407 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001408 return 0;
1409}
1410
1411/*
1412 * Close the multicast socket, and clear the vif tables etc
1413 */
1414
Yuval Mintzb70432f2018-02-28 23:29:32 +02001415static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001416{
Yuval Mintz494fff52018-02-28 23:29:34 +02001417 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001418 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001419 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001420
Yuval Mintz87c418b2018-02-28 23:29:31 +02001421 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001422 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001423 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001424 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001425 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001426 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001427 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001428
Yuval Mintz87c418b2018-02-28 23:29:31 +02001429 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001430 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001431 if (!all && (c->mfc_flags & MFC_STATIC))
1432 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001433 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001434 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001435 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
1436 ip6mr_cache_free((struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001437 }
1438
Patrick McHardy6bd52142010-05-11 14:40:53 +02001439 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001440 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001441 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001442 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001443 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1444 RTM_DELROUTE);
1445 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001446 }
1447 spin_unlock_bh(&mfc_unres_lock);
1448 }
1449}
1450
Yuval Mintzb70432f2018-02-28 23:29:32 +02001451static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001452{
1453 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001454 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001455
1456 rtnl_lock();
1457 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001458 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001459 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001460 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001461 rcu_assign_pointer(mrt->mroute_sk, sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001462 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001463 }
1464 write_unlock_bh(&mrt_lock);
1465
1466 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001467 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1468 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001469 NETCONFA_IFINDEX_ALL,
1470 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001471 rtnl_unlock();
1472
1473 return err;
1474}
1475
1476int ip6mr_sk_done(struct sock *sk)
1477{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001478 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001479 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001480 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001481
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001482 if (sk->sk_type != SOCK_RAW ||
1483 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1484 return err;
1485
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001486 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001487 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001488 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001489 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001490 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001491 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001492 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001493 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001494 NETCONFA_MC_FORWARDING,
1495 NETCONFA_IFINDEX_ALL,
1496 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001497
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001498 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001499 err = 0;
1500 break;
1501 }
1502 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001503 rtnl_unlock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001504 synchronize_rcu();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001505
1506 return err;
1507}
1508
Yuval Mintz8571ab42018-02-28 23:29:30 +02001509bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001510{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001511 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001512 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001513 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001514 .flowi6_oif = skb->dev->ifindex,
1515 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001516 };
1517
David S. Miller4c9483b2011-03-12 16:22:43 -05001518 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001519 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001520
Yuval Mintzb70432f2018-02-28 23:29:32 +02001521 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001522}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001523EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001524
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001525/*
1526 * Socket options and virtual interface manipulation. The whole
1527 * virtual interface system is a complete heap, but unfortunately
1528 * that's how BSD mrouted happens to think. Maybe one day with a proper
1529 * MOSPF/PIM router set up we can clean this up.
1530 */
1531
David S. Millerb7058842009-09-30 16:12:20 -07001532int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001533{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001534 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001535 struct mif6ctl vif;
1536 struct mf6cctl mfc;
1537 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001538 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001539 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001540
Xin Long99253eb2017-02-24 16:29:06 +08001541 if (sk->sk_type != SOCK_RAW ||
1542 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1543 return -EOPNOTSUPP;
1544
Patrick McHardyd1db2752010-05-11 14:40:55 +02001545 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001546 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001547 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001548
1549 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001550 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001551 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001552 return -EACCES;
1553 }
1554
1555 switch (optname) {
1556 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001557 if (optlen < sizeof(int))
1558 return -EINVAL;
1559
Patrick McHardy6bd52142010-05-11 14:40:53 +02001560 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001561
1562 case MRT6_DONE:
1563 return ip6mr_sk_done(sk);
1564
1565 case MRT6_ADD_MIF:
1566 if (optlen < sizeof(vif))
1567 return -EINVAL;
1568 if (copy_from_user(&vif, optval, sizeof(vif)))
1569 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001570 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001571 return -ENFILE;
1572 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001573 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001574 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001575 rtnl_unlock();
1576 return ret;
1577
1578 case MRT6_DEL_MIF:
1579 if (optlen < sizeof(mifi_t))
1580 return -EINVAL;
1581 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1582 return -EFAULT;
1583 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001584 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001585 rtnl_unlock();
1586 return ret;
1587
1588 /*
1589 * Manipulate the forwarding caches. These live
1590 * in a sort of kernel/user symbiosis.
1591 */
1592 case MRT6_ADD_MFC:
1593 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001594 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001595 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001596 case MRT6_ADD_MFC_PROXY:
1597 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001598 if (optlen < sizeof(mfc))
1599 return -EINVAL;
1600 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1601 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001602 if (parent == 0)
1603 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001604 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001605 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1606 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001607 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001608 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001609 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001610 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001611 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001612 rtnl_unlock();
1613 return ret;
1614
1615 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001616 * Control PIM assert (to activate pim will activate assert)
1617 */
1618 case MRT6_ASSERT:
1619 {
1620 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001621
1622 if (optlen != sizeof(v))
1623 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001624 if (get_user(v, (int __user *)optval))
1625 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001626 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001627 return 0;
1628 }
1629
1630#ifdef CONFIG_IPV6_PIMSM_V2
1631 case MRT6_PIM:
1632 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001633 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001634
1635 if (optlen != sizeof(v))
1636 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001637 if (get_user(v, (int __user *)optval))
1638 return -EFAULT;
1639 v = !!v;
1640 rtnl_lock();
1641 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001642 if (v != mrt->mroute_do_pim) {
1643 mrt->mroute_do_pim = v;
1644 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001645 }
1646 rtnl_unlock();
1647 return ret;
1648 }
1649
1650#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001651#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1652 case MRT6_TABLE:
1653 {
1654 u32 v;
1655
1656 if (optlen != sizeof(u32))
1657 return -EINVAL;
1658 if (get_user(v, (u32 __user *)optval))
1659 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001660 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1661 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1662 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001663 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001664 return -EBUSY;
1665
1666 rtnl_lock();
1667 ret = 0;
1668 if (!ip6mr_new_table(net, v))
1669 ret = -ENOMEM;
1670 raw6_sk(sk)->ip6mr_table = v;
1671 rtnl_unlock();
1672 return ret;
1673 }
1674#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001675 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001676 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001677 * set.
1678 */
1679 default:
1680 return -ENOPROTOOPT;
1681 }
1682}
1683
1684/*
1685 * Getsock opt support for the multicast routing system.
1686 */
1687
1688int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1689 int __user *optlen)
1690{
1691 int olr;
1692 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001693 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001694 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001695
Xin Long99253eb2017-02-24 16:29:06 +08001696 if (sk->sk_type != SOCK_RAW ||
1697 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1698 return -EOPNOTSUPP;
1699
Patrick McHardyd1db2752010-05-11 14:40:55 +02001700 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001701 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001702 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001703
1704 switch (optname) {
1705 case MRT6_VERSION:
1706 val = 0x0305;
1707 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001708#ifdef CONFIG_IPV6_PIMSM_V2
1709 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001710 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001711 break;
1712#endif
1713 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001714 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001715 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001716 default:
1717 return -ENOPROTOOPT;
1718 }
1719
1720 if (get_user(olr, optlen))
1721 return -EFAULT;
1722
1723 olr = min_t(int, olr, sizeof(int));
1724 if (olr < 0)
1725 return -EINVAL;
1726
1727 if (put_user(olr, optlen))
1728 return -EFAULT;
1729 if (copy_to_user(optval, &val, olr))
1730 return -EFAULT;
1731 return 0;
1732}
1733
1734/*
1735 * The IP multicast ioctl support routines.
1736 */
1737
1738int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1739{
1740 struct sioc_sg_req6 sr;
1741 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001742 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001743 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001744 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001745 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001746
1747 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001748 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001749 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001750
1751 switch (cmd) {
1752 case SIOCGETMIFCNT_IN6:
1753 if (copy_from_user(&vr, arg, sizeof(vr)))
1754 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001755 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001756 return -EINVAL;
1757 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001758 vif = &mrt->vif_table[vr.mifi];
1759 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001760 vr.icount = vif->pkt_in;
1761 vr.ocount = vif->pkt_out;
1762 vr.ibytes = vif->bytes_in;
1763 vr.obytes = vif->bytes_out;
1764 read_unlock(&mrt_lock);
1765
1766 if (copy_to_user(arg, &vr, sizeof(vr)))
1767 return -EFAULT;
1768 return 0;
1769 }
1770 read_unlock(&mrt_lock);
1771 return -EADDRNOTAVAIL;
1772 case SIOCGETSGCNT_IN6:
1773 if (copy_from_user(&sr, arg, sizeof(sr)))
1774 return -EFAULT;
1775
Yuval Mintz87c418b2018-02-28 23:29:31 +02001776 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001777 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001778 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001779 sr.pktcnt = c->_c.mfc_un.res.pkt;
1780 sr.bytecnt = c->_c.mfc_un.res.bytes;
1781 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001782 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001783
1784 if (copy_to_user(arg, &sr, sizeof(sr)))
1785 return -EFAULT;
1786 return 0;
1787 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001788 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001789 return -EADDRNOTAVAIL;
1790 default:
1791 return -ENOIOCTLCMD;
1792 }
1793}
1794
David S. Millere2d57762011-02-03 17:59:32 -08001795#ifdef CONFIG_COMPAT
1796struct compat_sioc_sg_req6 {
1797 struct sockaddr_in6 src;
1798 struct sockaddr_in6 grp;
1799 compat_ulong_t pktcnt;
1800 compat_ulong_t bytecnt;
1801 compat_ulong_t wrong_if;
1802};
1803
1804struct compat_sioc_mif_req6 {
1805 mifi_t mifi;
1806 compat_ulong_t icount;
1807 compat_ulong_t ocount;
1808 compat_ulong_t ibytes;
1809 compat_ulong_t obytes;
1810};
1811
1812int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1813{
1814 struct compat_sioc_sg_req6 sr;
1815 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001816 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001817 struct mfc6_cache *c;
1818 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001819 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001820
1821 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001822 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001823 return -ENOENT;
1824
1825 switch (cmd) {
1826 case SIOCGETMIFCNT_IN6:
1827 if (copy_from_user(&vr, arg, sizeof(vr)))
1828 return -EFAULT;
1829 if (vr.mifi >= mrt->maxvif)
1830 return -EINVAL;
1831 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001832 vif = &mrt->vif_table[vr.mifi];
1833 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001834 vr.icount = vif->pkt_in;
1835 vr.ocount = vif->pkt_out;
1836 vr.ibytes = vif->bytes_in;
1837 vr.obytes = vif->bytes_out;
1838 read_unlock(&mrt_lock);
1839
1840 if (copy_to_user(arg, &vr, sizeof(vr)))
1841 return -EFAULT;
1842 return 0;
1843 }
1844 read_unlock(&mrt_lock);
1845 return -EADDRNOTAVAIL;
1846 case SIOCGETSGCNT_IN6:
1847 if (copy_from_user(&sr, arg, sizeof(sr)))
1848 return -EFAULT;
1849
Yuval Mintz87c418b2018-02-28 23:29:31 +02001850 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001851 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1852 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001853 sr.pktcnt = c->_c.mfc_un.res.pkt;
1854 sr.bytecnt = c->_c.mfc_un.res.bytes;
1855 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001856 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001857
1858 if (copy_to_user(arg, &sr, sizeof(sr)))
1859 return -EFAULT;
1860 return 0;
1861 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001862 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001863 return -EADDRNOTAVAIL;
1864 default:
1865 return -ENOIOCTLCMD;
1866 }
1867}
1868#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001869
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001870static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001871{
Eric Dumazet1d015502016-04-27 16:44:40 -07001872 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1873 IPSTATS_MIB_OUTFORWDATAGRAMS);
1874 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1875 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001876 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001877}
1878
1879/*
1880 * Processing handlers for ip6mr_forward
1881 */
1882
Yuval Mintzb70432f2018-02-28 23:29:32 +02001883static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001884 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001885{
1886 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001887 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001888 struct net_device *dev;
1889 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001890 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001891
Ian Morris63159f22015-03-29 14:00:04 +01001892 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001893 goto out_free;
1894
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001895#ifdef CONFIG_IPV6_PIMSM_V2
1896 if (vif->flags & MIFF_REGISTER) {
1897 vif->pkt_out++;
1898 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001899 vif->dev->stats.tx_bytes += skb->len;
1900 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001901 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001902 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001903 }
1904#endif
1905
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001906 ipv6h = ipv6_hdr(skb);
1907
David S. Miller4c9483b2011-03-12 16:22:43 -05001908 fl6 = (struct flowi6) {
1909 .flowi6_oif = vif->link,
1910 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001911 };
1912
David S. Miller4c9483b2011-03-12 16:22:43 -05001913 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001914 if (dst->error) {
1915 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001916 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00001917 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001918
Eric Dumazetadf30902009-06-02 05:19:30 +00001919 skb_dst_drop(skb);
1920 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001921
1922 /*
1923 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1924 * not only before forwarding, but after forwarding on all output
1925 * interfaces. It is clear, if mrouter runs a multicasting
1926 * program, it should receive packets not depending to what interface
1927 * program is joined.
1928 * If we will not make it, the program will have to join on all
1929 * interfaces. On the other hand, multihoming host (or router, but
1930 * not mrouter) cannot join to more than one interface - it will
1931 * result in receiving multiple packets.
1932 */
1933 dev = vif->dev;
1934 skb->dev = dev;
1935 vif->pkt_out++;
1936 vif->bytes_out += skb->len;
1937
1938 /* We are about to write */
1939 /* XXX: extension headers? */
1940 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
1941 goto out_free;
1942
1943 ipv6h = ipv6_hdr(skb);
1944 ipv6h->hop_limit--;
1945
1946 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
1947
Eric W. Biederman29a26a52015-09-15 20:04:16 -05001948 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
1949 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001950 ip6mr_forward2_finish);
1951
1952out_free:
1953 kfree_skb(skb);
1954 return 0;
1955}
1956
Yuval Mintzb70432f2018-02-28 23:29:32 +02001957static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001958{
1959 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001960
1961 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001962 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001963 break;
1964 }
1965 return ct;
1966}
1967
Yuval Mintzb70432f2018-02-28 23:29:32 +02001968static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +02001969 struct sk_buff *skb, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001970{
1971 int psend = -1;
1972 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001973 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001974
Yuval Mintz494fff52018-02-28 23:29:34 +02001975 vif = c->_c.mfc_parent;
1976 c->_c.mfc_un.res.pkt++;
1977 c->_c.mfc_un.res.bytes += skb->len;
1978 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001979
Yuval Mintz494fff52018-02-28 23:29:34 +02001980 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001981 struct mfc6_cache *cache_proxy;
1982
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01001983 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001984 * interface is part of the static tree.
1985 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02001986 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02001987 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001988 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02001989 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001990 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001991 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001992 }
1993 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001994 }
1995
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001996 /*
1997 * Wrong interface: drop packet and (maybe) send PIM assert.
1998 */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001999 if (mrt->vif_table[vif].dev != skb->dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002000 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002001
Patrick McHardy6bd52142010-05-11 14:40:53 +02002002 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002003 /* pimsm uses asserts, when switching from RPT to SPT,
2004 so that we cannot check that packet arrived on an oif.
2005 It is bad, but otherwise we would need to move pretty
2006 large chunk of pimd to kernel. Ough... --ANK
2007 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002008 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02002009 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002010 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02002011 c->_c.mfc_un.res.last_assert +
2012 MFC_ASSERT_THRESH)) {
2013 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002014 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002015 }
2016 goto dont_forward;
2017 }
2018
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002019forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02002020 mrt->vif_table[vif].pkt_in++;
2021 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002022
2023 /*
2024 * Forward the frame
2025 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002026 if (ipv6_addr_any(&c->mf6c_origin) &&
2027 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002028 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002029 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002030 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02002031 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002032 /* It's an (*,*) entry and the packet is not coming from
2033 * the upstream: forward the packet to the upstream
2034 * only.
2035 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002036 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002037 goto last_forward;
2038 }
2039 goto dont_forward;
2040 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002041 for (ct = c->_c.mfc_un.res.maxvif - 1;
2042 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002043 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002044 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2045 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002046 if (psend != -1) {
2047 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2048 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002049 ip6mr_forward2(net, mrt, skb2,
2050 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002051 }
2052 psend = ct;
2053 }
2054 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002055last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002056 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002057 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002058 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002059 }
2060
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002061dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002062 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002063}
2064
2065
2066/*
2067 * Multicast packets for forwarding arrive here
2068 */
2069
2070int ip6_mr_input(struct sk_buff *skb)
2071{
2072 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002073 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002074 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002075 struct flowi6 fl6 = {
2076 .flowi6_iif = skb->dev->ifindex,
2077 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002078 };
2079 int err;
2080
David S. Miller4c9483b2011-03-12 16:22:43 -05002081 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002082 if (err < 0) {
2083 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002084 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002085 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002086
2087 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002088 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002089 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002090 if (!cache) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002091 int vif = ip6mr_find_vif(mrt, skb->dev);
2092
2093 if (vif >= 0)
2094 cache = ip6mr_cache_find_any(mrt,
2095 &ipv6_hdr(skb)->daddr,
2096 vif);
2097 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002098
2099 /*
2100 * No usable cache entry
2101 */
Ian Morris63159f22015-03-29 14:00:04 +01002102 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002103 int vif;
2104
Patrick McHardy6bd52142010-05-11 14:40:53 +02002105 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002106 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002107 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002108 read_unlock(&mrt_lock);
2109
2110 return err;
2111 }
2112 read_unlock(&mrt_lock);
2113 kfree_skb(skb);
2114 return -ENODEV;
2115 }
2116
Patrick McHardy6bd52142010-05-11 14:40:53 +02002117 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002118
2119 read_unlock(&mrt_lock);
2120
2121 return 0;
2122}
2123
2124
Yuval Mintzb70432f2018-02-28 23:29:32 +02002125static int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002126 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002127{
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002128 struct rta_mfc_stats mfcs;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002129 struct nlattr *mp_attr;
2130 struct rtnexthop *nhp;
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002131 unsigned long lastuse;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002132 int ct;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002133
Nicolas Dichtel74381892010-03-25 23:45:35 +00002134 /* If cache is unresolved, don't try to parse IIF and OIF */
Yuval Mintz494fff52018-02-28 23:29:34 +02002135 if (c->_c.mfc_parent >= MAXMIFS) {
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002136 rtm->rtm_flags |= RTNH_F_UNRESOLVED;
Nicolas Dichtel74381892010-03-25 23:45:35 +00002137 return -ENOENT;
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002138 }
Nicolas Dichtel74381892010-03-25 23:45:35 +00002139
Yuval Mintz494fff52018-02-28 23:29:34 +02002140 if (VIF_EXISTS(mrt, c->_c.mfc_parent) &&
Yuval Mintzb70432f2018-02-28 23:29:32 +02002141 nla_put_u32(skb, RTA_IIF,
Yuval Mintz494fff52018-02-28 23:29:34 +02002142 mrt->vif_table[c->_c.mfc_parent].dev->ifindex) < 0)
Thomas Graf74a0bd72012-06-26 23:36:14 +00002143 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002144 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
Ian Morris63159f22015-03-29 14:00:04 +01002145 if (!mp_attr)
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002146 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002147
Yuval Mintz494fff52018-02-28 23:29:34 +02002148 for (ct = c->_c.mfc_un.res.minvif;
2149 ct < c->_c.mfc_un.res.maxvif; ct++) {
2150 if (VIF_EXISTS(mrt, ct) && c->_c.mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002151 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
Ian Morris63159f22015-03-29 14:00:04 +01002152 if (!nhp) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002153 nla_nest_cancel(skb, mp_attr);
2154 return -EMSGSIZE;
2155 }
2156
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002157 nhp->rtnh_flags = 0;
Yuval Mintz494fff52018-02-28 23:29:34 +02002158 nhp->rtnh_hops = c->_c.mfc_un.res.ttls[ct];
Yuval Mintzb70432f2018-02-28 23:29:32 +02002159 nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002160 nhp->rtnh_len = sizeof(*nhp);
2161 }
2162 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002163
2164 nla_nest_end(skb, mp_attr);
2165
Yuval Mintz494fff52018-02-28 23:29:34 +02002166 lastuse = READ_ONCE(c->_c.mfc_un.res.lastuse);
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002167 lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
2168
Yuval Mintz494fff52018-02-28 23:29:34 +02002169 mfcs.mfcs_packets = c->_c.mfc_un.res.pkt;
2170 mfcs.mfcs_bytes = c->_c.mfc_un.res.bytes;
2171 mfcs.mfcs_wrong_if = c->_c.mfc_un.res.wrong_if;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002172 if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002173 nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002174 RTA_PAD))
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002175 return -EMSGSIZE;
2176
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002177 rtm->rtm_type = RTN_MULTICAST;
2178 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002179}
2180
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002181int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002182 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002183{
2184 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002185 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002186 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002187 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002188
Patrick McHardyd1db2752010-05-11 14:40:55 +02002189 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002190 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002191 return -ENOENT;
2192
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002193 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002194 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002195 if (!cache && skb->dev) {
2196 int vif = ip6mr_find_vif(mrt, skb->dev);
2197
2198 if (vif >= 0)
2199 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2200 vif);
2201 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002202
2203 if (!cache) {
2204 struct sk_buff *skb2;
2205 struct ipv6hdr *iph;
2206 struct net_device *dev;
2207 int vif;
2208
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002209 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002210 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002211 read_unlock(&mrt_lock);
2212 return -ENODEV;
2213 }
2214
2215 /* really correct? */
2216 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2217 if (!skb2) {
2218 read_unlock(&mrt_lock);
2219 return -ENOMEM;
2220 }
2221
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002222 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002223 skb_reset_transport_header(skb2);
2224
2225 skb_put(skb2, sizeof(struct ipv6hdr));
2226 skb_reset_network_header(skb2);
2227
2228 iph = ipv6_hdr(skb2);
2229 iph->version = 0;
2230 iph->priority = 0;
2231 iph->flow_lbl[0] = 0;
2232 iph->flow_lbl[1] = 0;
2233 iph->flow_lbl[2] = 0;
2234 iph->payload_len = 0;
2235 iph->nexthdr = IPPROTO_NONE;
2236 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002237 iph->saddr = rt->rt6i_src.addr;
2238 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002239
Patrick McHardy6bd52142010-05-11 14:40:53 +02002240 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002241 read_unlock(&mrt_lock);
2242
2243 return err;
2244 }
2245
David Ahernfd61c6b2017-01-17 15:51:07 -08002246 if (rtm->rtm_flags & RTM_F_NOTIFY)
Yuval Mintz494fff52018-02-28 23:29:34 +02002247 cache->_c.mfc_flags |= MFC_NOTIFY;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002248
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002249 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002250 read_unlock(&mrt_lock);
2251 return err;
2252}
2253
Yuval Mintzb70432f2018-02-28 23:29:32 +02002254static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002255 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2256 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002257{
2258 struct nlmsghdr *nlh;
2259 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002260 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002261
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002262 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002263 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002264 return -EMSGSIZE;
2265
2266 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002267 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002268 rtm->rtm_dst_len = 128;
2269 rtm->rtm_src_len = 128;
2270 rtm->rtm_tos = 0;
2271 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002272 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2273 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002274 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002275 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002276 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002277 rtm->rtm_protocol = RTPROT_STATIC;
2278 else
2279 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002280 rtm->rtm_flags = 0;
2281
Jiri Benc930345e2015-03-29 16:59:25 +02002282 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2283 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002284 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002285 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2286 /* do not break the dump if cache is unresolved */
2287 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002288 goto nla_put_failure;
2289
Johannes Berg053c0952015-01-16 22:09:00 +01002290 nlmsg_end(skb, nlh);
2291 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002292
2293nla_put_failure:
2294 nlmsg_cancel(skb, nlh);
2295 return -EMSGSIZE;
2296}
2297
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002298static int mr6_msgsize(bool unresolved, int maxvif)
2299{
2300 size_t len =
2301 NLMSG_ALIGN(sizeof(struct rtmsg))
2302 + nla_total_size(4) /* RTA_TABLE */
2303 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2304 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2305 ;
2306
2307 if (!unresolved)
2308 len = len
2309 + nla_total_size(4) /* RTA_IIF */
2310 + nla_total_size(0) /* RTA_MULTIPATH */
2311 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2312 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002313 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002314 ;
2315
2316 return len;
2317}
2318
Yuval Mintzb70432f2018-02-28 23:29:32 +02002319static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002320 int cmd)
2321{
2322 struct net *net = read_pnet(&mrt->net);
2323 struct sk_buff *skb;
2324 int err = -ENOBUFS;
2325
Yuval Mintz494fff52018-02-28 23:29:34 +02002326 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002327 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002328 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002329 goto errout;
2330
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002331 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002332 if (err < 0)
2333 goto errout;
2334
2335 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2336 return;
2337
2338errout:
2339 kfree_skb(skb);
2340 if (err < 0)
2341 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2342}
2343
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002344static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2345{
2346 size_t len =
2347 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2348 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2349 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2350 /* IP6MRA_CREPORT_SRC_ADDR */
2351 + nla_total_size(sizeof(struct in6_addr))
2352 /* IP6MRA_CREPORT_DST_ADDR */
2353 + nla_total_size(sizeof(struct in6_addr))
2354 /* IP6MRA_CREPORT_PKT */
2355 + nla_total_size(payloadlen)
2356 ;
2357
2358 return len;
2359}
2360
Yuval Mintzb70432f2018-02-28 23:29:32 +02002361static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002362{
2363 struct net *net = read_pnet(&mrt->net);
2364 struct nlmsghdr *nlh;
2365 struct rtgenmsg *rtgenm;
2366 struct mrt6msg *msg;
2367 struct sk_buff *skb;
2368 struct nlattr *nla;
2369 int payloadlen;
2370
2371 payloadlen = pkt->len - sizeof(struct mrt6msg);
2372 msg = (struct mrt6msg *)skb_transport_header(pkt);
2373
2374 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2375 if (!skb)
2376 goto errout;
2377
2378 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2379 sizeof(struct rtgenmsg), 0);
2380 if (!nlh)
2381 goto errout;
2382 rtgenm = nlmsg_data(nlh);
2383 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2384 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2385 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2386 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2387 &msg->im6_src) ||
2388 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2389 &msg->im6_dst))
2390 goto nla_put_failure;
2391
2392 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2393 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2394 nla_data(nla), payloadlen))
2395 goto nla_put_failure;
2396
2397 nlmsg_end(skb, nlh);
2398
2399 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2400 return;
2401
2402nla_put_failure:
2403 nlmsg_cancel(skb, nlh);
2404errout:
2405 kfree_skb(skb);
2406 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2407}
2408
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002409static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2410{
2411 struct net *net = sock_net(skb->sk);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002412 unsigned int t = 0, s_t;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002413 unsigned int e = 0, s_e;
Yuval Mintz494fff52018-02-28 23:29:34 +02002414 struct mr_table *mrt;
2415 struct mr_mfc *mfc;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002416
2417 s_t = cb->args[0];
Yuval Mintz87c418b2018-02-28 23:29:31 +02002418 s_e = cb->args[1];
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002419
Yuval Mintz87c418b2018-02-28 23:29:31 +02002420 rcu_read_lock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002421 ip6mr_for_each_table(mrt, net) {
2422 if (t < s_t)
2423 goto next_table;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002424 list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002425 if (e < s_e)
2426 goto next_entry;
2427 if (ip6mr_fill_mroute(mrt, skb,
2428 NETLINK_CB(cb->skb).portid,
2429 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002430 (struct mfc6_cache *)mfc,
2431 RTM_NEWROUTE, NLM_F_MULTI) < 0)
Yuval Mintz87c418b2018-02-28 23:29:31 +02002432 goto done;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002433next_entry:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002434 e++;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002435 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02002436 e = 0;
2437 s_e = 0;
2438
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002439 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002440 list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002441 if (e < s_e)
2442 goto next_entry2;
2443 if (ip6mr_fill_mroute(mrt, skb,
2444 NETLINK_CB(cb->skb).portid,
2445 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002446 (struct mfc6_cache *)mfc,
2447 RTM_NEWROUTE, NLM_F_MULTI) < 0) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002448 spin_unlock_bh(&mfc_unres_lock);
2449 goto done;
2450 }
2451next_entry2:
2452 e++;
2453 }
2454 spin_unlock_bh(&mfc_unres_lock);
2455 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002456next_table:
2457 t++;
2458 }
2459done:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002460 rcu_read_unlock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002461
Yuval Mintz87c418b2018-02-28 23:29:31 +02002462 cb->args[1] = e;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002463 cb->args[0] = t;
2464
2465 return skb->len;
2466}