blob: ea902a952fb6ec79c9cc92389a8e9814f2249642 [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
336
337struct ipmr_mfc_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800338 struct seq_net_private p;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200339 struct mr_table *mrt;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200340 struct list_head *cache;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900341};
342
343
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800344static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
345 struct ipmr_mfc_iter *it, loff_t pos)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900346{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200347 struct mr_table *mrt = it->mrt;
Yuval Mintz494fff52018-02-28 23:29:34 +0200348 struct mr_mfc *mfc;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900349
Yuval Mintz87c418b2018-02-28 23:29:31 +0200350 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +0200351 it->cache = &mrt->mfc_cache_list;
352 list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
Yuval Mintz87c418b2018-02-28 23:29:31 +0200353 if (pos-- == 0)
Yuval Mintz494fff52018-02-28 23:29:34 +0200354 return (struct mfc6_cache *)mfc;
Yuval Mintz87c418b2018-02-28 23:29:31 +0200355 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900356
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900357 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200358 it->cache = &mrt->mfc_unres_queue;
Patrick McHardyf30a77842010-05-11 14:40:51 +0200359 list_for_each_entry(mfc, it->cache, list)
Patrick McHardyc476efb2010-05-11 14:40:48 +0200360 if (pos-- == 0)
Yuval Mintz494fff52018-02-28 23:29:34 +0200361 return (struct mfc6_cache *)mfc;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900362 spin_unlock_bh(&mfc_unres_lock);
363
364 it->cache = NULL;
365 return NULL;
366}
367
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900368/*
369 * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
370 */
371
372struct ipmr_vif_iter {
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800373 struct seq_net_private p;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200374 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900375 int ct;
376};
377
Yuval Mintz6853f212018-02-28 23:29:29 +0200378static struct vif_device *ip6mr_vif_seq_idx(struct net *net,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800379 struct ipmr_vif_iter *iter,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900380 loff_t pos)
381{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200382 struct mr_table *mrt = iter->mrt;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200383
384 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200385 if (!VIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900386 continue;
387 if (pos-- == 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200388 return &mrt->vif_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900389 }
390 return NULL;
391}
392
393static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
394 __acquires(mrt_lock)
395{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200396 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800397 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200398 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200399
400 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100401 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200402 return ERR_PTR(-ENOENT);
403
404 iter->mrt = mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800405
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900406 read_lock(&mrt_lock);
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800407 return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
408 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900409}
410
411static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
412{
413 struct ipmr_vif_iter *iter = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800414 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200415 struct mr_table *mrt = iter->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900416
417 ++*pos;
418 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800419 return ip6mr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900420
Patrick McHardy6bd52142010-05-11 14:40:53 +0200421 while (++iter->ct < mrt->maxvif) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200422 if (!VIF_EXISTS(mrt, iter->ct))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900423 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200424 return &mrt->vif_table[iter->ct];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900425 }
426 return NULL;
427}
428
429static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
430 __releases(mrt_lock)
431{
432 read_unlock(&mrt_lock);
433}
434
435static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
436{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200437 struct ipmr_vif_iter *iter = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200438 struct mr_table *mrt = iter->mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800439
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900440 if (v == SEQ_START_TOKEN) {
441 seq_puts(seq,
442 "Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
443 } else {
Yuval Mintz6853f212018-02-28 23:29:29 +0200444 const struct vif_device *vif = v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900445 const char *name = vif->dev ? vif->dev->name : "none";
446
447 seq_printf(seq,
Al Virod430a222008-06-02 10:59:02 +0100448 "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
Yuval Mintzb70432f2018-02-28 23:29:32 +0200449 vif - mrt->vif_table,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900450 name, vif->bytes_in, vif->pkt_in,
451 vif->bytes_out, vif->pkt_out,
452 vif->flags);
453 }
454 return 0;
455}
456
Stephen Hemminger98147d52009-09-01 19:25:02 +0000457static const struct seq_operations ip6mr_vif_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900458 .start = ip6mr_vif_seq_start,
459 .next = ip6mr_vif_seq_next,
460 .stop = ip6mr_vif_seq_stop,
461 .show = ip6mr_vif_seq_show,
462};
463
464static int ip6mr_vif_open(struct inode *inode, struct file *file)
465{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800466 return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
467 sizeof(struct ipmr_vif_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900468}
469
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000470static const struct file_operations ip6mr_vif_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900471 .open = ip6mr_vif_open,
472 .read = seq_read,
473 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800474 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900475};
476
477static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
478{
Patrick McHardyd1db2752010-05-11 14:40:55 +0200479 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800480 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200481 struct mr_table *mrt;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800482
Patrick McHardyd1db2752010-05-11 14:40:55 +0200483 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +0100484 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200485 return ERR_PTR(-ENOENT);
486
487 it->mrt = mrt;
Nikolay Aleksandrov4adfa792018-01-31 16:29:30 +0200488 it->cache = NULL;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800489 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
490 : SEQ_START_TOKEN;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900491}
492
493static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
494{
495 struct mfc6_cache *mfc = v;
496 struct ipmr_mfc_iter *it = seq->private;
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800497 struct net *net = seq_file_net(seq);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200498 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900499
500 ++*pos;
501
502 if (v == SEQ_START_TOKEN)
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800503 return ipmr_mfc_seq_idx(net, seq->private, 0);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900504
Yuval Mintz494fff52018-02-28 23:29:34 +0200505 if (mfc->_c.list.next != it->cache)
506 return (struct mfc6_cache *)(list_entry(mfc->_c.list.next,
507 struct mr_mfc, list));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900508
Yuval Mintzb70432f2018-02-28 23:29:32 +0200509 if (it->cache == &mrt->mfc_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900510 goto end_of_list;
511
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900512 /* exhausted cache_array, show unresolved */
Yuval Mintz87c418b2018-02-28 23:29:31 +0200513 rcu_read_unlock();
Yuval Mintzb70432f2018-02-28 23:29:32 +0200514 it->cache = &mrt->mfc_unres_queue;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900515
516 spin_lock_bh(&mfc_unres_lock);
Patrick McHardyf30a77842010-05-11 14:40:51 +0200517 if (!list_empty(it->cache))
Yuval Mintz494fff52018-02-28 23:29:34 +0200518 return (struct mfc6_cache *)(list_first_entry(it->cache,
519 struct mr_mfc,
520 list));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900521
522 end_of_list:
523 spin_unlock_bh(&mfc_unres_lock);
524 it->cache = NULL;
525
526 return NULL;
527}
528
529static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
530{
531 struct ipmr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200532 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900533
Yuval Mintzb70432f2018-02-28 23:29:32 +0200534 if (it->cache == &mrt->mfc_unres_queue)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900535 spin_unlock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200536 else if (it->cache == &mrt->mfc_cache_list)
Yuval Mintz87c418b2018-02-28 23:29:31 +0200537 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900538}
539
540static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
541{
542 int n;
543
544 if (v == SEQ_START_TOKEN) {
545 seq_puts(seq,
546 "Group "
547 "Origin "
548 "Iif Pkts Bytes Wrong Oifs\n");
549 } else {
550 const struct mfc6_cache *mfc = v;
551 const struct ipmr_mfc_iter *it = seq->private;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200552 struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900553
Benjamin Thery999890b2008-12-03 22:22:16 -0800554 seq_printf(seq, "%pI6 %pI6 %-3hd",
Harvey Harrison0c6ce782008-10-28 16:09:23 -0700555 &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
Yuval Mintz494fff52018-02-28 23:29:34 +0200556 mfc->_c.mfc_parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900557
Yuval Mintzb70432f2018-02-28 23:29:32 +0200558 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800559 seq_printf(seq, " %8lu %8lu %8lu",
Yuval Mintz494fff52018-02-28 23:29:34 +0200560 mfc->_c.mfc_un.res.pkt,
561 mfc->_c.mfc_un.res.bytes,
562 mfc->_c.mfc_un.res.wrong_if);
563 for (n = mfc->_c.mfc_un.res.minvif;
564 n < mfc->_c.mfc_un.res.maxvif; n++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200565 if (VIF_EXISTS(mrt, n) &&
Yuval Mintz494fff52018-02-28 23:29:34 +0200566 mfc->_c.mfc_un.res.ttls[n] < 255)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900567 seq_printf(seq,
Yuval Mintz494fff52018-02-28 23:29:34 +0200568 " %2d:%-3d", n,
569 mfc->_c.mfc_un.res.ttls[n]);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900570 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -0800571 } else {
572 /* unresolved mfc_caches don't contain
573 * pkt, bytes and wrong_if values
574 */
575 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900576 }
577 seq_putc(seq, '\n');
578 }
579 return 0;
580}
581
James Morris88e9d342009-09-22 16:43:43 -0700582static const struct seq_operations ipmr_mfc_seq_ops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900583 .start = ipmr_mfc_seq_start,
584 .next = ipmr_mfc_seq_next,
585 .stop = ipmr_mfc_seq_stop,
586 .show = ipmr_mfc_seq_show,
587};
588
589static int ipmr_mfc_open(struct inode *inode, struct file *file)
590{
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800591 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
592 sizeof(struct ipmr_mfc_iter));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900593}
594
Stephen Hemminger5ca1b992009-09-01 19:25:05 +0000595static const struct file_operations ip6mr_mfc_fops = {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900596 .open = ipmr_mfc_open,
597 .read = seq_read,
598 .llseek = seq_lseek,
Benjamin Thery8b90fc72008-12-10 16:29:48 -0800599 .release = seq_release_net,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900600};
601#endif
602
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900603#ifdef CONFIG_IPV6_PIMSM_V2
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900604
605static int pim6_rcv(struct sk_buff *skb)
606{
607 struct pimreghdr *pim;
608 struct ipv6hdr *encap;
609 struct net_device *reg_dev = NULL;
Benjamin Thery8229efd2008-12-10 16:30:15 -0800610 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200611 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500612 struct flowi6 fl6 = {
613 .flowi6_iif = skb->dev->ifindex,
614 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200615 };
616 int reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900617
618 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
619 goto drop;
620
621 pim = (struct pimreghdr *)skb_transport_header(skb);
Nikolay Aleksandrov56245ca2016-10-31 13:21:04 +0100622 if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900623 (pim->flags & PIM_NULL_REGISTER) ||
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800624 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
625 sizeof(*pim), IPPROTO_PIM,
626 csum_partial((void *)pim, sizeof(*pim), 0)) &&
Al Viroec6b4862008-04-26 22:28:58 -0700627 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900628 goto drop;
629
630 /* check if the inner packet is destined to mcast group */
631 encap = (struct ipv6hdr *)(skb_transport_header(skb) +
632 sizeof(*pim));
633
634 if (!ipv6_addr_is_multicast(&encap->daddr) ||
635 encap->payload_len == 0 ||
636 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
637 goto drop;
638
David S. Miller4c9483b2011-03-12 16:22:43 -0500639 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +0200640 goto drop;
641 reg_vif_num = mrt->mroute_reg_vif_num;
642
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900643 read_lock(&mrt_lock);
644 if (reg_vif_num >= 0)
Yuval Mintzb70432f2018-02-28 23:29:32 +0200645 reg_dev = mrt->vif_table[reg_vif_num].dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900646 if (reg_dev)
647 dev_hold(reg_dev);
648 read_unlock(&mrt_lock);
649
Ian Morris63159f22015-03-29 14:00:04 +0100650 if (!reg_dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900651 goto drop;
652
653 skb->mac_header = skb->network_header;
654 skb_pull(skb, (u8 *)encap - skb->data);
655 skb_reset_network_header(skb);
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800656 skb->protocol = htons(ETH_P_IPV6);
Cesar Eduardo Barros3e49e6d2011-03-26 05:10:30 +0000657 skb->ip_summed = CHECKSUM_NONE;
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700658
Nicolas Dichtelea231922013-09-02 15:34:58 +0200659 skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
Eric Dumazetd19d56d2010-05-17 22:36:55 -0700660
Eric Dumazetcaf586e2010-09-30 21:06:55 +0000661 netif_rx(skb);
Eric Dumazet8990f462010-09-20 00:12:11 +0000662
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900663 dev_put(reg_dev);
664 return 0;
665 drop:
666 kfree_skb(skb);
667 return 0;
668}
669
Alexey Dobriyan41135cc2009-09-14 12:22:28 +0000670static const struct inet6_protocol pim6_protocol = {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900671 .handler = pim6_rcv,
672};
673
674/* Service routines creating virtual interfaces: PIMREG */
675
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000676static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
677 struct net_device *dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900678{
Benjamin Thery8229efd2008-12-10 16:30:15 -0800679 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +0200680 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -0500681 struct flowi6 fl6 = {
682 .flowi6_oif = dev->ifindex,
Cong Wang6a662712014-04-15 16:25:34 -0700683 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -0500684 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +0200685 };
686 int err;
687
David S. Miller4c9483b2011-03-12 16:22:43 -0500688 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear67928c42011-09-23 13:11:01 +0000689 if (err < 0) {
690 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +0200691 return err;
Ben Greear67928c42011-09-23 13:11:01 +0000692 }
Benjamin Thery8229efd2008-12-10 16:30:15 -0800693
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900694 read_lock(&mrt_lock);
Pavel Emelyanovdc58c782008-05-21 14:17:54 -0700695 dev->stats.tx_bytes += skb->len;
696 dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200697 ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900698 read_unlock(&mrt_lock);
699 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000700 return NETDEV_TX_OK;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900701}
702
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200703static int reg_vif_get_iflink(const struct net_device *dev)
704{
705 return 0;
706}
707
Stephen Hemminger007c3832008-11-20 20:28:35 -0800708static const struct net_device_ops reg_vif_netdev_ops = {
709 .ndo_start_xmit = reg_vif_xmit,
Nicolas Dichtelee9b9592015-04-02 17:07:03 +0200710 .ndo_get_iflink = reg_vif_get_iflink,
Stephen Hemminger007c3832008-11-20 20:28:35 -0800711};
712
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900713static void reg_vif_setup(struct net_device *dev)
714{
715 dev->type = ARPHRD_PIMREG;
716 dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
717 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800718 dev->netdev_ops = &reg_vif_netdev_ops;
David S. Millercf124db2017-05-08 12:52:56 -0400719 dev->needs_free_netdev = true;
Tom Goff403dbb92009-06-14 03:16:13 -0700720 dev->features |= NETIF_F_NETNS_LOCAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900721}
722
Yuval Mintzb70432f2018-02-28 23:29:32 +0200723static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900724{
725 struct net_device *dev;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200726 char name[IFNAMSIZ];
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900727
Patrick McHardyd1db2752010-05-11 14:40:55 +0200728 if (mrt->id == RT6_TABLE_DFLT)
729 sprintf(name, "pim6reg");
730 else
731 sprintf(name, "pim6reg%u", mrt->id);
732
Tom Gundersenc835a672014-07-14 16:37:24 +0200733 dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
Ian Morris63159f22015-03-29 14:00:04 +0100734 if (!dev)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900735 return NULL;
736
Benjamin Thery8229efd2008-12-10 16:30:15 -0800737 dev_net_set(dev, net);
738
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900739 if (register_netdevice(dev)) {
740 free_netdev(dev);
741 return NULL;
742 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900743
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900744 if (dev_open(dev))
745 goto failure;
746
Wang Chen7af3db72008-07-14 20:54:54 -0700747 dev_hold(dev);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900748 return dev;
749
750failure:
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900751 unregister_netdevice(dev);
752 return NULL;
753}
754#endif
755
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900756/*
757 * Delete a VIF entry
758 */
759
Yuval Mintzb70432f2018-02-28 23:29:32 +0200760static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300761 struct list_head *head)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900762{
Yuval Mintz6853f212018-02-28 23:29:29 +0200763 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900764 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800765 struct inet6_dev *in6_dev;
Patrick McHardy6bd52142010-05-11 14:40:53 +0200766
767 if (vifi < 0 || vifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900768 return -EADDRNOTAVAIL;
769
Yuval Mintzb70432f2018-02-28 23:29:32 +0200770 v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900771
772 write_lock_bh(&mrt_lock);
773 dev = v->dev;
774 v->dev = NULL;
775
776 if (!dev) {
777 write_unlock_bh(&mrt_lock);
778 return -EADDRNOTAVAIL;
779 }
780
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900781#ifdef CONFIG_IPV6_PIMSM_V2
Patrick McHardy6bd52142010-05-11 14:40:53 +0200782 if (vifi == mrt->mroute_reg_vif_num)
783 mrt->mroute_reg_vif_num = -1;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900784#endif
785
Patrick McHardy6bd52142010-05-11 14:40:53 +0200786 if (vifi + 1 == mrt->maxvif) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900787 int tmp;
788 for (tmp = vifi - 1; tmp >= 0; tmp--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200789 if (VIF_EXISTS(mrt, tmp))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900790 break;
791 }
Patrick McHardy6bd52142010-05-11 14:40:53 +0200792 mrt->maxvif = tmp + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900793 }
794
795 write_unlock_bh(&mrt_lock);
796
797 dev_set_allmulti(dev, -1);
798
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800799 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000800 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800801 in6_dev->cnf.mc_forwarding--;
David Ahern85b3daa2017-03-28 14:28:04 -0700802 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000803 NETCONFA_MC_FORWARDING,
804 dev->ifindex, &in6_dev->cnf);
805 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800806
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +0300807 if ((v->flags & MIFF_REGISTER) && !notify)
Eric Dumazetc871e662009-10-28 04:48:11 +0000808 unregister_netdevice_queue(dev, head);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900809
810 dev_put(dev);
811 return 0;
812}
813
Yuval Mintz87c418b2018-02-28 23:29:31 +0200814static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
815{
Yuval Mintz494fff52018-02-28 23:29:34 +0200816 struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200817
Yuval Mintz494fff52018-02-28 23:29:34 +0200818 kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
Yuval Mintz87c418b2018-02-28 23:29:31 +0200819}
820
Benjamin Thery58701ad2008-12-10 16:22:34 -0800821static inline void ip6mr_cache_free(struct mfc6_cache *c)
822{
Yuval Mintz494fff52018-02-28 23:29:34 +0200823 call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
Benjamin Thery58701ad2008-12-10 16:22:34 -0800824}
825
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900826/* Destroy an unresolved cache entry, killing queued skbs
827 and reporting error to netlink readers.
828 */
829
Yuval Mintzb70432f2018-02-28 23:29:32 +0200830static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900831{
Patrick McHardy6bd52142010-05-11 14:40:53 +0200832 struct net *net = read_pnet(&mrt->net);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900833 struct sk_buff *skb;
834
Patrick McHardy6bd52142010-05-11 14:40:53 +0200835 atomic_dec(&mrt->cache_resolve_queue_len);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900836
Yuval Mintz494fff52018-02-28 23:29:34 +0200837 while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900838 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +0200839 struct nlmsghdr *nlh = skb_pull(skb,
840 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900841 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +0000842 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900843 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +0000844 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000845 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900846 } else
847 kfree_skb(skb);
848 }
849
Benjamin Thery58701ad2008-12-10 16:22:34 -0800850 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900851}
852
853
Patrick McHardyc476efb2010-05-11 14:40:48 +0200854/* Timer process for all the unresolved queue. */
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900855
Yuval Mintzb70432f2018-02-28 23:29:32 +0200856static void ipmr_do_expire_process(struct mr_table *mrt)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900857{
858 unsigned long now = jiffies;
859 unsigned long expires = 10 * HZ;
Yuval Mintz494fff52018-02-28 23:29:34 +0200860 struct mr_mfc *c, *next;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900861
Yuval Mintzb70432f2018-02-28 23:29:32 +0200862 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900863 if (time_after(c->mfc_un.unres.expires, now)) {
864 /* not yet... */
865 unsigned long interval = c->mfc_un.unres.expires - now;
866 if (interval < expires)
867 expires = interval;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900868 continue;
869 }
870
Patrick McHardyf30a77842010-05-11 14:40:51 +0200871 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +0200872 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
873 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900874 }
875
Yuval Mintzb70432f2018-02-28 23:29:32 +0200876 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200877 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900878}
879
Kees Cooke99e88a2017-10-16 14:43:17 -0700880static void ipmr_expire_process(struct timer_list *t)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900881{
Yuval Mintzb70432f2018-02-28 23:29:32 +0200882 struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
Patrick McHardyc476efb2010-05-11 14:40:48 +0200883
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900884 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy6bd52142010-05-11 14:40:53 +0200885 mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900886 return;
887 }
888
Yuval Mintzb70432f2018-02-28 23:29:32 +0200889 if (!list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +0200890 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900891
892 spin_unlock(&mfc_unres_lock);
893}
894
895/* Fill oifs list. It is called under write locked mrt_lock. */
896
Yuval Mintzb70432f2018-02-28 23:29:32 +0200897static void ip6mr_update_thresholds(struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +0200898 struct mr_mfc *cache,
Patrick McHardyb5aa30b2010-05-11 14:40:50 +0200899 unsigned char *ttls)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900900{
901 int vifi;
902
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300903 cache->mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900904 cache->mfc_un.res.maxvif = 0;
Rami Rosen6ac7eb02008-04-10 12:40:10 +0300905 memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900906
Patrick McHardy6bd52142010-05-11 14:40:53 +0200907 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +0200908 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Thery4e168802008-12-10 16:15:08 -0800909 ttls[vifi] && ttls[vifi] < 255) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900910 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
911 if (cache->mfc_un.res.minvif > vifi)
912 cache->mfc_un.res.minvif = vifi;
913 if (cache->mfc_un.res.maxvif <= vifi)
914 cache->mfc_un.res.maxvif = vifi + 1;
915 }
916 }
Nikolay Aleksandrov90b5ca12016-07-26 18:54:52 +0200917 cache->mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900918}
919
Yuval Mintzb70432f2018-02-28 23:29:32 +0200920static int mif6_add(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +0200921 struct mif6ctl *vifc, int mrtsock)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900922{
923 int vifi = vifc->mif6c_mifi;
Yuval Mintzb70432f2018-02-28 23:29:32 +0200924 struct vif_device *v = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900925 struct net_device *dev;
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800926 struct inet6_dev *in6_dev;
Wang Chen5ae7b442008-07-14 20:54:23 -0700927 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900928
929 /* Is vif busy ? */
Yuval Mintzb70432f2018-02-28 23:29:32 +0200930 if (VIF_EXISTS(mrt, vifi))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900931 return -EADDRINUSE;
932
933 switch (vifc->mif6c_flags) {
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900934#ifdef CONFIG_IPV6_PIMSM_V2
935 case MIFF_REGISTER:
936 /*
937 * Special Purpose VIF in PIM
938 * All the packets will be sent to the daemon
939 */
Patrick McHardy6bd52142010-05-11 14:40:53 +0200940 if (mrt->mroute_reg_vif_num >= 0)
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900941 return -EADDRINUSE;
Patrick McHardyd1db2752010-05-11 14:40:55 +0200942 dev = ip6mr_reg_vif(net, mrt);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900943 if (!dev)
944 return -ENOBUFS;
Wang Chen5ae7b442008-07-14 20:54:23 -0700945 err = dev_set_allmulti(dev, 1);
946 if (err) {
947 unregister_netdevice(dev);
Wang Chen7af3db72008-07-14 20:54:54 -0700948 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700949 return err;
950 }
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900951 break;
952#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900953 case 0:
Benjamin Thery8229efd2008-12-10 16:30:15 -0800954 dev = dev_get_by_index(net, vifc->mif6c_pifi);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900955 if (!dev)
956 return -EADDRNOTAVAIL;
Wang Chen5ae7b442008-07-14 20:54:23 -0700957 err = dev_set_allmulti(dev, 1);
Wang Chen7af3db72008-07-14 20:54:54 -0700958 if (err) {
959 dev_put(dev);
Wang Chen5ae7b442008-07-14 20:54:23 -0700960 return err;
Wang Chen7af3db72008-07-14 20:54:54 -0700961 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900962 break;
963 default:
964 return -EINVAL;
965 }
966
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800967 in6_dev = __in6_dev_get(dev);
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000968 if (in6_dev) {
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800969 in6_dev->cnf.mc_forwarding++;
David Ahern85b3daa2017-03-28 14:28:04 -0700970 inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +0000971 NETCONFA_MC_FORWARDING,
972 dev->ifindex, &in6_dev->cnf);
973 }
Thomas Goff1d6e55f2009-01-27 22:39:59 -0800974
Yuval Mintz6853f212018-02-28 23:29:29 +0200975 /* Fill in the VIF structures */
976 vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
977 vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
978 MIFF_REGISTER);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900979
980 /* And finish update writing critical data */
981 write_lock_bh(&mrt_lock);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900982 v->dev = dev;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900983#ifdef CONFIG_IPV6_PIMSM_V2
984 if (v->flags & MIFF_REGISTER)
Patrick McHardy6bd52142010-05-11 14:40:53 +0200985 mrt->mroute_reg_vif_num = vifi;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +0900986#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +0200987 if (vifi + 1 > mrt->maxvif)
988 mrt->maxvif = vifi + 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900989 write_unlock_bh(&mrt_lock);
990 return 0;
991}
992
Yuval Mintzb70432f2018-02-28 23:29:32 +0200993static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000994 const struct in6_addr *origin,
995 const struct in6_addr *mcastgrp)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +0900996{
Yuval Mintz87c418b2018-02-28 23:29:31 +0200997 struct mfc6_cache_cmp_arg arg = {
998 .mf6c_origin = *origin,
999 .mf6c_mcastgrp = *mcastgrp,
1000 };
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001001
Yuval Mintz845c9a72018-02-28 23:29:35 +02001002 return mr_mfc_find(mrt, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001003}
1004
1005/* Look for a (*,G) entry */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001006static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001007 struct in6_addr *mcastgrp,
1008 mifi_t mifi)
1009{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001010 struct mfc6_cache_cmp_arg arg = {
1011 .mf6c_origin = in6addr_any,
1012 .mf6c_mcastgrp = *mcastgrp,
1013 };
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001014
1015 if (ipv6_addr_any(mcastgrp))
Yuval Mintz845c9a72018-02-28 23:29:35 +02001016 return mr_mfc_find_any_parent(mrt, mifi);
1017 return mr_mfc_find_any(mrt, mifi, &arg);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001018}
1019
Yuval Mintz87c418b2018-02-28 23:29:31 +02001020/* Look for a (S,G,iif) entry if parent != -1 */
1021static struct mfc6_cache *
Yuval Mintzb70432f2018-02-28 23:29:32 +02001022ip6mr_cache_find_parent(struct mr_table *mrt,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001023 const struct in6_addr *origin,
1024 const struct in6_addr *mcastgrp,
1025 int parent)
1026{
1027 struct mfc6_cache_cmp_arg arg = {
1028 .mf6c_origin = *origin,
1029 .mf6c_mcastgrp = *mcastgrp,
1030 };
Yuval Mintz87c418b2018-02-28 23:29:31 +02001031
Yuval Mintz845c9a72018-02-28 23:29:35 +02001032 return mr_mfc_find_parent(mrt, &arg, parent);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001033}
1034
Yuval Mintz845c9a72018-02-28 23:29:35 +02001035/* Allocate a multicast cache entry */
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001036static struct mfc6_cache *ip6mr_cache_alloc(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001037{
Joe Perches36cbac52008-12-03 22:27:25 -08001038 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
Ian Morris63159f22015-03-29 14:00:04 +01001039 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001040 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +02001041 c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
1042 c->_c.mfc_un.res.minvif = MAXMIFS;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001043 return c;
1044}
1045
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001046static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001047{
Joe Perches36cbac52008-12-03 22:27:25 -08001048 struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01001049 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001050 return NULL;
Yuval Mintz494fff52018-02-28 23:29:34 +02001051 skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
1052 c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001053 return c;
1054}
1055
1056/*
1057 * A cache entry has gone into a resolved state from queued
1058 */
1059
Yuval Mintzb70432f2018-02-28 23:29:32 +02001060static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001061 struct mfc6_cache *uc, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001062{
1063 struct sk_buff *skb;
1064
1065 /*
1066 * Play the pending entries through our router
1067 */
1068
Yuval Mintz494fff52018-02-28 23:29:34 +02001069 while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001070 if (ipv6_hdr(skb)->version == 0) {
Johannes Bergaf728682017-06-16 14:29:22 +02001071 struct nlmsghdr *nlh = skb_pull(skb,
1072 sizeof(struct ipv6hdr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001073
Hong zhi guo573ce262013-03-27 06:47:04 +00001074 if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
YOSHIFUJI Hideaki549e0282008-04-05 22:17:39 +09001075 nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001076 } else {
1077 nlh->nlmsg_type = NLMSG_ERROR;
Hong zhi guo573ce262013-03-27 06:47:04 +00001078 nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001079 skb_trim(skb, nlh->nlmsg_len);
Hong zhi guo573ce262013-03-27 06:47:04 +00001080 ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001081 }
Eric W. Biederman15e47302012-09-07 20:12:54 +00001082 rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001083 } else
Patrick McHardy6bd52142010-05-11 14:40:53 +02001084 ip6_mr_forward(net, mrt, skb, c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001085 }
1086}
1087
1088/*
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001089 * Bounce a cache query up to pim6sd and netlink.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001090 *
1091 * Called under mrt_lock.
1092 */
1093
Yuval Mintzb70432f2018-02-28 23:29:32 +02001094static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001095 mifi_t mifi, int assert)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001096{
Yuval Mintz8571ab42018-02-28 23:29:30 +02001097 struct sock *mroute6_sk;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001098 struct sk_buff *skb;
1099 struct mrt6msg *msg;
1100 int ret;
1101
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001102#ifdef CONFIG_IPV6_PIMSM_V2
1103 if (assert == MRT6MSG_WHOLEPKT)
1104 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1105 +sizeof(*msg));
1106 else
1107#endif
1108 skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001109
1110 if (!skb)
1111 return -ENOBUFS;
1112
1113 /* I suppose that internal messages
1114 * do not require checksums */
1115
1116 skb->ip_summed = CHECKSUM_UNNECESSARY;
1117
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001118#ifdef CONFIG_IPV6_PIMSM_V2
1119 if (assert == MRT6MSG_WHOLEPKT) {
1120 /* Ugly, but we have no choice with this interface.
1121 Duplicate old header, fix length etc.
1122 And all this only to mangle msg->im6_msgtype and
1123 to set msg->im6_mbz to "mbz" :-)
1124 */
1125 skb_push(skb, -skb_network_offset(pkt));
1126
1127 skb_push(skb, sizeof(*msg));
1128 skb_reset_transport_header(skb);
1129 msg = (struct mrt6msg *)skb_transport_header(skb);
1130 msg->im6_mbz = 0;
1131 msg->im6_msgtype = MRT6MSG_WHOLEPKT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001132 msg->im6_mif = mrt->mroute_reg_vif_num;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001133 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001134 msg->im6_src = ipv6_hdr(pkt)->saddr;
1135 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001136
1137 skb->ip_summed = CHECKSUM_UNNECESSARY;
1138 } else
1139#endif
1140 {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001141 /*
1142 * Copy the IP header
1143 */
1144
1145 skb_put(skb, sizeof(struct ipv6hdr));
1146 skb_reset_network_header(skb);
1147 skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
1148
1149 /*
1150 * Add our header
1151 */
1152 skb_put(skb, sizeof(*msg));
1153 skb_reset_transport_header(skb);
1154 msg = (struct mrt6msg *)skb_transport_header(skb);
1155
1156 msg->im6_mbz = 0;
1157 msg->im6_msgtype = assert;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001158 msg->im6_mif = mifi;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001159 msg->im6_pad = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00001160 msg->im6_src = ipv6_hdr(pkt)->saddr;
1161 msg->im6_dst = ipv6_hdr(pkt)->daddr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001162
Eric Dumazetadf30902009-06-02 05:19:30 +00001163 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001164 skb->ip_summed = CHECKSUM_UNNECESSARY;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001165 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001166
Yuval Mintz8571ab42018-02-28 23:29:30 +02001167 rcu_read_lock();
Yuval Mintzb70432f2018-02-28 23:29:32 +02001168 mroute6_sk = rcu_dereference(mrt->mroute_sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001169 if (!mroute6_sk) {
1170 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001171 kfree_skb(skb);
1172 return -EINVAL;
1173 }
1174
Julien Gomesdd12d15c2017-06-20 13:54:18 -07001175 mrt6msg_netlink_event(mrt, skb);
1176
Yuval Mintz8571ab42018-02-28 23:29:30 +02001177 /* Deliver to user space multicast routing algorithms */
1178 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1179 rcu_read_unlock();
Benjamin Therybd91b8b2008-12-10 16:07:08 -08001180 if (ret < 0) {
Joe Perchese87cc472012-05-13 21:56:26 +00001181 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001182 kfree_skb(skb);
1183 }
1184
1185 return ret;
1186}
1187
Yuval Mintz494fff52018-02-28 23:29:34 +02001188/* Queue a packet for resolution. It gets locked cache entry! */
1189static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
1190 struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001191{
Yuval Mintz494fff52018-02-28 23:29:34 +02001192 struct mfc6_cache *c;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001193 bool found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001194 int err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001195
1196 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001197 list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
Patrick McHardyc476efb2010-05-11 14:40:48 +02001198 if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
Patrick McHardyf30a77842010-05-11 14:40:51 +02001199 ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
1200 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001201 break;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001202 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001203 }
1204
Patrick McHardyf30a77842010-05-11 14:40:51 +02001205 if (!found) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001206 /*
1207 * Create a new entry if allowable
1208 */
1209
Patrick McHardy6bd52142010-05-11 14:40:53 +02001210 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001211 (c = ip6mr_cache_alloc_unres()) == NULL) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001212 spin_unlock_bh(&mfc_unres_lock);
1213
1214 kfree_skb(skb);
1215 return -ENOBUFS;
1216 }
1217
Yuval Mintz494fff52018-02-28 23:29:34 +02001218 /* Fill in the new cache entry */
1219 c->_c.mfc_parent = -1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001220 c->mf6c_origin = ipv6_hdr(skb)->saddr;
1221 c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
1222
1223 /*
1224 * Reflect first query at pim6sd
1225 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001226 err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001227 if (err < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001228 /* If the report failed throw the cache entry
1229 out - Brad Parker
1230 */
1231 spin_unlock_bh(&mfc_unres_lock);
1232
Benjamin Thery58701ad2008-12-10 16:22:34 -08001233 ip6mr_cache_free(c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001234 kfree_skb(skb);
1235 return err;
1236 }
1237
Patrick McHardy6bd52142010-05-11 14:40:53 +02001238 atomic_inc(&mrt->cache_resolve_queue_len);
Yuval Mintz494fff52018-02-28 23:29:34 +02001239 list_add(&c->_c.list, &mrt->mfc_unres_queue);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001240 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001241
Patrick McHardy6bd52142010-05-11 14:40:53 +02001242 ipmr_do_expire_process(mrt);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001243 }
1244
Yuval Mintz494fff52018-02-28 23:29:34 +02001245 /* See if we can append the packet */
1246 if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001247 kfree_skb(skb);
1248 err = -ENOBUFS;
1249 } else {
Yuval Mintz494fff52018-02-28 23:29:34 +02001250 skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001251 err = 0;
1252 }
1253
1254 spin_unlock_bh(&mfc_unres_lock);
1255 return err;
1256}
1257
1258/*
1259 * MFC6 cache manipulation by user space
1260 */
1261
Yuval Mintzb70432f2018-02-28 23:29:32 +02001262static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001263 int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001264{
Yuval Mintz87c418b2018-02-28 23:29:31 +02001265 struct mfc6_cache *c;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001266
Yuval Mintz87c418b2018-02-28 23:29:31 +02001267 /* The entries are added/deleted only under RTNL */
1268 rcu_read_lock();
1269 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1270 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1271 rcu_read_unlock();
1272 if (!c)
1273 return -ENOENT;
Yuval Mintz494fff52018-02-28 23:29:34 +02001274 rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
1275 list_del_rcu(&c->_c.list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001276
Yuval Mintz87c418b2018-02-28 23:29:31 +02001277 mr6_netlink_event(mrt, c, RTM_DELROUTE);
1278 ip6mr_cache_free(c);
1279 return 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001280}
1281
1282static int ip6mr_device_event(struct notifier_block *this,
1283 unsigned long event, void *ptr)
1284{
Jiri Pirko351638e2013-05-28 01:30:21 +00001285 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
Benjamin Thery8229efd2008-12-10 16:30:15 -08001286 struct net *net = dev_net(dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001287 struct mr_table *mrt;
Yuval Mintz6853f212018-02-28 23:29:29 +02001288 struct vif_device *v;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001289 int ct;
1290
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001291 if (event != NETDEV_UNREGISTER)
1292 return NOTIFY_DONE;
1293
Patrick McHardyd1db2752010-05-11 14:40:55 +02001294 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001295 v = &mrt->vif_table[0];
Patrick McHardyd1db2752010-05-11 14:40:55 +02001296 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1297 if (v->dev == dev)
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001298 mif6_delete(mrt, ct, 1, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001299 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001300 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001301
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001302 return NOTIFY_DONE;
1303}
1304
1305static struct notifier_block ip6_mr_notifier = {
1306 .notifier_call = ip6mr_device_event
1307};
1308
1309/*
1310 * Setup for IP multicast routing
1311 */
1312
Benjamin Thery4e168802008-12-10 16:15:08 -08001313static int __net_init ip6mr_net_init(struct net *net)
1314{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001315 int err;
Patrick McHardyf30a77842010-05-11 14:40:51 +02001316
Patrick McHardyd1db2752010-05-11 14:40:55 +02001317 err = ip6mr_rules_init(net);
1318 if (err < 0)
Benjamin Thery4e168802008-12-10 16:15:08 -08001319 goto fail;
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001320
1321#ifdef CONFIG_PROC_FS
1322 err = -ENOMEM;
Gao fengd4beaa62013-02-18 01:34:54 +00001323 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001324 goto proc_vif_fail;
Gao fengd4beaa62013-02-18 01:34:54 +00001325 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001326 goto proc_cache_fail;
1327#endif
Patrick McHardy6bd52142010-05-11 14:40:53 +02001328
Benjamin Thery4a6258a2008-12-10 16:24:07 -08001329 return 0;
1330
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001331#ifdef CONFIG_PROC_FS
1332proc_cache_fail:
Gao fengece31ff2013-02-18 01:34:56 +00001333 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001334proc_vif_fail:
Patrick McHardyd1db2752010-05-11 14:40:55 +02001335 ip6mr_rules_exit(net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001336#endif
Benjamin Thery4e168802008-12-10 16:15:08 -08001337fail:
1338 return err;
1339}
1340
1341static void __net_exit ip6mr_net_exit(struct net *net)
1342{
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001343#ifdef CONFIG_PROC_FS
Gao fengece31ff2013-02-18 01:34:56 +00001344 remove_proc_entry("ip6_mr_cache", net->proc_net);
1345 remove_proc_entry("ip6_mr_vif", net->proc_net);
Benjamin Thery8b90fc72008-12-10 16:29:48 -08001346#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001347 ip6mr_rules_exit(net);
Benjamin Thery4e168802008-12-10 16:15:08 -08001348}
1349
1350static struct pernet_operations ip6mr_net_ops = {
1351 .init = ip6mr_net_init,
1352 .exit = ip6mr_net_exit,
Kirill Tkhaib01a59a2018-02-19 11:48:37 +03001353 .async = true,
Benjamin Thery4e168802008-12-10 16:15:08 -08001354};
1355
Wang Chen623d1a12008-07-03 12:13:30 +08001356int __init ip6_mr_init(void)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001357{
Wang Chen623d1a12008-07-03 12:13:30 +08001358 int err;
1359
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001360 mrt_cachep = kmem_cache_create("ip6_mrt_cache",
1361 sizeof(struct mfc6_cache),
1362 0, SLAB_HWCACHE_ALIGN,
1363 NULL);
1364 if (!mrt_cachep)
Wang Chen623d1a12008-07-03 12:13:30 +08001365 return -ENOMEM;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001366
Benjamin Thery4e168802008-12-10 16:15:08 -08001367 err = register_pernet_subsys(&ip6mr_net_ops);
1368 if (err)
1369 goto reg_pernet_fail;
1370
Wang Chen623d1a12008-07-03 12:13:30 +08001371 err = register_netdevice_notifier(&ip6_mr_notifier);
1372 if (err)
1373 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07001374#ifdef CONFIG_IPV6_PIMSM_V2
1375 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
Joe Perchesf3213832012-05-15 14:11:53 +00001376 pr_err("%s: can't add PIM protocol\n", __func__);
Tom Goff403dbb92009-06-14 03:16:13 -07001377 err = -EAGAIN;
1378 goto add_proto_fail;
1379 }
1380#endif
Florian Westphala3fde2a2017-12-04 19:19:18 +01001381 err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
1382 NULL, ip6mr_rtm_dumproute, 0);
1383 if (err == 0)
1384 return 0;
1385
Tom Goff403dbb92009-06-14 03:16:13 -07001386#ifdef CONFIG_IPV6_PIMSM_V2
Florian Westphala3fde2a2017-12-04 19:19:18 +01001387 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
Tom Goff403dbb92009-06-14 03:16:13 -07001388add_proto_fail:
1389 unregister_netdevice_notifier(&ip6_mr_notifier);
1390#endif
Benjamin Thery87b30a62008-11-10 16:34:11 -08001391reg_notif_fail:
Benjamin Thery4e168802008-12-10 16:15:08 -08001392 unregister_pernet_subsys(&ip6mr_net_ops);
1393reg_pernet_fail:
Benjamin Thery87b30a62008-11-10 16:34:11 -08001394 kmem_cache_destroy(mrt_cachep);
Wang Chen623d1a12008-07-03 12:13:30 +08001395 return err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001396}
1397
Wang Chen623d1a12008-07-03 12:13:30 +08001398void ip6_mr_cleanup(void)
1399{
Duan Jiongffb13882014-11-19 09:35:39 +08001400 rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
1401#ifdef CONFIG_IPV6_PIMSM_V2
1402 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
1403#endif
Wang Chen623d1a12008-07-03 12:13:30 +08001404 unregister_netdevice_notifier(&ip6_mr_notifier);
Benjamin Thery4e168802008-12-10 16:15:08 -08001405 unregister_pernet_subsys(&ip6mr_net_ops);
Wang Chen623d1a12008-07-03 12:13:30 +08001406 kmem_cache_destroy(mrt_cachep);
1407}
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001408
Yuval Mintzb70432f2018-02-28 23:29:32 +02001409static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001410 struct mf6cctl *mfc, int mrtsock, int parent)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001411{
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001412 unsigned char ttls[MAXMIFS];
Yuval Mintz87c418b2018-02-28 23:29:31 +02001413 struct mfc6_cache *uc, *c;
Yuval Mintz494fff52018-02-28 23:29:34 +02001414 struct mr_mfc *_uc;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001415 bool found;
1416 int i, err;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001417
Patrick McHardya50436f22010-03-17 06:04:14 +00001418 if (mfc->mf6cc_parent >= MAXMIFS)
1419 return -ENFILE;
1420
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001421 memset(ttls, 255, MAXMIFS);
1422 for (i = 0; i < MAXMIFS; i++) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001423 if (IF_ISSET(i, &mfc->mf6cc_ifset))
1424 ttls[i] = 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001425 }
1426
Yuval Mintz87c418b2018-02-28 23:29:31 +02001427 /* The entries are added/deleted only under RTNL */
1428 rcu_read_lock();
1429 c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
1430 &mfc->mf6cc_mcastgrp.sin6_addr, parent);
1431 rcu_read_unlock();
1432 if (c) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001433 write_lock_bh(&mrt_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001434 c->_c.mfc_parent = mfc->mf6cc_parent;
1435 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001436 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001437 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001438 write_unlock_bh(&mrt_lock);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001439 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001440 return 0;
1441 }
1442
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001443 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1444 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001445 return -EINVAL;
1446
Patrick McHardyb5aa30b2010-05-11 14:40:50 +02001447 c = ip6mr_cache_alloc();
Ian Morris63159f22015-03-29 14:00:04 +01001448 if (!c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001449 return -ENOMEM;
1450
1451 c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
1452 c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
Yuval Mintz494fff52018-02-28 23:29:34 +02001453 c->_c.mfc_parent = mfc->mf6cc_parent;
1454 ip6mr_update_thresholds(mrt, &c->_c, ttls);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001455 if (!mrtsock)
Yuval Mintz494fff52018-02-28 23:29:34 +02001456 c->_c.mfc_flags |= MFC_STATIC;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001457
Yuval Mintz494fff52018-02-28 23:29:34 +02001458 err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
Yuval Mintz87c418b2018-02-28 23:29:31 +02001459 ip6mr_rht_params);
1460 if (err) {
1461 pr_err("ip6mr: rhtable insert error %d\n", err);
1462 ip6mr_cache_free(c);
1463 return err;
1464 }
Yuval Mintz494fff52018-02-28 23:29:34 +02001465 list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001466
Yuval Mintz87c418b2018-02-28 23:29:31 +02001467 /* Check to see if we resolved a queued list. If so we
1468 * need to send on the frames and tidy up.
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001469 */
Patrick McHardyf30a77842010-05-11 14:40:51 +02001470 found = false;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001471 spin_lock_bh(&mfc_unres_lock);
Yuval Mintz494fff52018-02-28 23:29:34 +02001472 list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
1473 uc = (struct mfc6_cache *)_uc;
Patrick McHardyc476efb2010-05-11 14:40:48 +02001474 if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001475 ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001476 list_del(&_uc->list);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001477 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyf30a77842010-05-11 14:40:51 +02001478 found = true;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001479 break;
1480 }
1481 }
Yuval Mintzb70432f2018-02-28 23:29:32 +02001482 if (list_empty(&mrt->mfc_unres_queue))
Patrick McHardy6bd52142010-05-11 14:40:53 +02001483 del_timer(&mrt->ipmr_expire_timer);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001484 spin_unlock_bh(&mfc_unres_lock);
1485
Patrick McHardyf30a77842010-05-11 14:40:51 +02001486 if (found) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02001487 ip6mr_cache_resolve(net, mrt, uc, c);
Benjamin Thery58701ad2008-12-10 16:22:34 -08001488 ip6mr_cache_free(uc);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001489 }
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00001490 mr6_netlink_event(mrt, c, RTM_NEWROUTE);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001491 return 0;
1492}
1493
1494/*
1495 * Close the multicast socket, and clear the vif tables etc
1496 */
1497
Yuval Mintzb70432f2018-02-28 23:29:32 +02001498static void mroute_clean_tables(struct mr_table *mrt, bool all)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001499{
Yuval Mintz494fff52018-02-28 23:29:34 +02001500 struct mr_mfc *c, *tmp;
Eric Dumazetc871e662009-10-28 04:48:11 +00001501 LIST_HEAD(list);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001502 int i;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001503
Yuval Mintz87c418b2018-02-28 23:29:31 +02001504 /* Shut down all active vif entries */
Patrick McHardy6bd52142010-05-11 14:40:53 +02001505 for (i = 0; i < mrt->maxvif; i++) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001506 if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001507 continue;
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001508 mif6_delete(mrt, i, 0, &list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001509 }
Eric Dumazetc871e662009-10-28 04:48:11 +00001510 unregister_netdevice_many(&list);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001511
Yuval Mintz87c418b2018-02-28 23:29:31 +02001512 /* Wipe the cache */
Yuval Mintzb70432f2018-02-28 23:29:32 +02001513 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02001514 if (!all && (c->mfc_flags & MFC_STATIC))
1515 continue;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001516 rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
Yuval Mintz87c418b2018-02-28 23:29:31 +02001517 list_del_rcu(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001518 mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
1519 ip6mr_cache_free((struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001520 }
1521
Patrick McHardy6bd52142010-05-11 14:40:53 +02001522 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001523 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001524 list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
Patrick McHardyf30a77842010-05-11 14:40:51 +02001525 list_del(&c->list);
Yuval Mintz494fff52018-02-28 23:29:34 +02001526 mr6_netlink_event(mrt, (struct mfc6_cache *)c,
1527 RTM_DELROUTE);
1528 ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001529 }
1530 spin_unlock_bh(&mfc_unres_lock);
1531 }
1532}
1533
Yuval Mintzb70432f2018-02-28 23:29:32 +02001534static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001535{
1536 int err = 0;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001537 struct net *net = sock_net(sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001538
1539 rtnl_lock();
1540 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001541 if (rtnl_dereference(mrt->mroute_sk)) {
Eric Dumazet927265b2016-07-08 05:46:04 +02001542 err = -EADDRINUSE;
Yuval Mintz8571ab42018-02-28 23:29:30 +02001543 } else {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001544 rcu_assign_pointer(mrt->mroute_sk, sk);
Yuval Mintz8571ab42018-02-28 23:29:30 +02001545 net->ipv6.devconf_all->mc_forwarding++;
Eric Dumazet927265b2016-07-08 05:46:04 +02001546 }
1547 write_unlock_bh(&mrt_lock);
1548
1549 if (!err)
David Ahern85b3daa2017-03-28 14:28:04 -07001550 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1551 NETCONFA_MC_FORWARDING,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001552 NETCONFA_IFINDEX_ALL,
1553 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001554 rtnl_unlock();
1555
1556 return err;
1557}
1558
1559int ip6mr_sk_done(struct sock *sk)
1560{
Patrick McHardyd1db2752010-05-11 14:40:55 +02001561 int err = -EACCES;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001562 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001563 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001564
Francesco Ruggeri338d1822017-11-08 11:23:46 -08001565 if (sk->sk_type != SOCK_RAW ||
1566 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1567 return err;
1568
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001569 rtnl_lock();
Patrick McHardyd1db2752010-05-11 14:40:55 +02001570 ip6mr_for_each_table(mrt, net) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001571 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyd1db2752010-05-11 14:40:55 +02001572 write_lock_bh(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001573 RCU_INIT_POINTER(mrt->mroute_sk, NULL);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001574 net->ipv6.devconf_all->mc_forwarding--;
Eric Dumazet927265b2016-07-08 05:46:04 +02001575 write_unlock_bh(&mrt_lock);
David Ahern85b3daa2017-03-28 14:28:04 -07001576 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
Nicolas Dichteld67b8c62012-12-04 01:13:35 +00001577 NETCONFA_MC_FORWARDING,
1578 NETCONFA_IFINDEX_ALL,
1579 net->ipv6.devconf_all);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001580
Nikolay Aleksandrov4c698042015-11-20 13:54:20 +01001581 mroute_clean_tables(mrt, false);
Patrick McHardyd1db2752010-05-11 14:40:55 +02001582 err = 0;
1583 break;
1584 }
1585 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001586 rtnl_unlock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001587 synchronize_rcu();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001588
1589 return err;
1590}
1591
Yuval Mintz8571ab42018-02-28 23:29:30 +02001592bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
Patrick McHardy6bd52142010-05-11 14:40:53 +02001593{
Yuval Mintzb70432f2018-02-28 23:29:32 +02001594 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05001595 struct flowi6 fl6 = {
Julian Anastasove374c612014-04-28 10:51:56 +03001596 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
David S. Miller4c9483b2011-03-12 16:22:43 -05001597 .flowi6_oif = skb->dev->ifindex,
1598 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02001599 };
1600
David S. Miller4c9483b2011-03-12 16:22:43 -05001601 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001602 return NULL;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001603
Yuval Mintzb70432f2018-02-28 23:29:32 +02001604 return rcu_access_pointer(mrt->mroute_sk);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001605}
Yuval Mintz8571ab42018-02-28 23:29:30 +02001606EXPORT_SYMBOL(mroute6_is_socket);
Patrick McHardy6bd52142010-05-11 14:40:53 +02001607
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001608/*
1609 * Socket options and virtual interface manipulation. The whole
1610 * virtual interface system is a complete heap, but unfortunately
1611 * that's how BSD mrouted happens to think. Maybe one day with a proper
1612 * MOSPF/PIM router set up we can clean this up.
1613 */
1614
David S. Millerb7058842009-09-30 16:12:20 -07001615int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001616{
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001617 int ret, parent = 0;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001618 struct mif6ctl vif;
1619 struct mf6cctl mfc;
1620 mifi_t mifi;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001621 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001622 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001623
Xin Long99253eb2017-02-24 16:29:06 +08001624 if (sk->sk_type != SOCK_RAW ||
1625 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1626 return -EOPNOTSUPP;
1627
Patrick McHardyd1db2752010-05-11 14:40:55 +02001628 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001629 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001630 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001631
1632 if (optname != MRT6_INIT) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02001633 if (sk != rcu_access_pointer(mrt->mroute_sk) &&
Yuval Mintz8571ab42018-02-28 23:29:30 +02001634 !ns_capable(net->user_ns, CAP_NET_ADMIN))
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001635 return -EACCES;
1636 }
1637
1638 switch (optname) {
1639 case MRT6_INIT:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001640 if (optlen < sizeof(int))
1641 return -EINVAL;
1642
Patrick McHardy6bd52142010-05-11 14:40:53 +02001643 return ip6mr_sk_init(mrt, sk);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001644
1645 case MRT6_DONE:
1646 return ip6mr_sk_done(sk);
1647
1648 case MRT6_ADD_MIF:
1649 if (optlen < sizeof(vif))
1650 return -EINVAL;
1651 if (copy_from_user(&vif, optval, sizeof(vif)))
1652 return -EFAULT;
Rami Rosen6ac7eb02008-04-10 12:40:10 +03001653 if (vif.mif6c_mifi >= MAXMIFS)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001654 return -ENFILE;
1655 rtnl_lock();
Yuval Mintz8571ab42018-02-28 23:29:30 +02001656 ret = mif6_add(net, mrt, &vif,
Yuval Mintzb70432f2018-02-28 23:29:32 +02001657 sk == rtnl_dereference(mrt->mroute_sk));
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001658 rtnl_unlock();
1659 return ret;
1660
1661 case MRT6_DEL_MIF:
1662 if (optlen < sizeof(mifi_t))
1663 return -EINVAL;
1664 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1665 return -EFAULT;
1666 rtnl_lock();
Nikolay Aleksandrov723b9292017-04-21 20:42:16 +03001667 ret = mif6_delete(mrt, mifi, 0, NULL);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001668 rtnl_unlock();
1669 return ret;
1670
1671 /*
1672 * Manipulate the forwarding caches. These live
1673 * in a sort of kernel/user symbiosis.
1674 */
1675 case MRT6_ADD_MFC:
1676 case MRT6_DEL_MFC:
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001677 parent = -1;
Gustavo A. R. Silva275757e62017-10-16 16:36:52 -05001678 /* fall through */
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001679 case MRT6_ADD_MFC_PROXY:
1680 case MRT6_DEL_MFC_PROXY:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001681 if (optlen < sizeof(mfc))
1682 return -EINVAL;
1683 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1684 return -EFAULT;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001685 if (parent == 0)
1686 parent = mfc.mf6cc_parent;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001687 rtnl_lock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001688 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1689 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001690 else
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00001691 ret = ip6mr_mfc_add(net, mrt, &mfc,
Yuval Mintz8571ab42018-02-28 23:29:30 +02001692 sk ==
Yuval Mintzb70432f2018-02-28 23:29:32 +02001693 rtnl_dereference(mrt->mroute_sk),
Yuval Mintz8571ab42018-02-28 23:29:30 +02001694 parent);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001695 rtnl_unlock();
1696 return ret;
1697
1698 /*
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001699 * Control PIM assert (to activate pim will activate assert)
1700 */
1701 case MRT6_ASSERT:
1702 {
1703 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001704
1705 if (optlen != sizeof(v))
1706 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001707 if (get_user(v, (int __user *)optval))
1708 return -EFAULT;
Joe Perches53d68412012-11-25 09:35:30 +00001709 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001710 return 0;
1711 }
1712
1713#ifdef CONFIG_IPV6_PIMSM_V2
1714 case MRT6_PIM:
1715 {
YOSHIFUJI Hideakia9f83bf2008-04-10 15:41:28 +09001716 int v;
Joe Perches03f52a02012-11-25 18:26:34 +00001717
1718 if (optlen != sizeof(v))
1719 return -EINVAL;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001720 if (get_user(v, (int __user *)optval))
1721 return -EFAULT;
1722 v = !!v;
1723 rtnl_lock();
1724 ret = 0;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001725 if (v != mrt->mroute_do_pim) {
1726 mrt->mroute_do_pim = v;
1727 mrt->mroute_do_assert = v;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001728 }
1729 rtnl_unlock();
1730 return ret;
1731 }
1732
1733#endif
Patrick McHardyd1db2752010-05-11 14:40:55 +02001734#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
1735 case MRT6_TABLE:
1736 {
1737 u32 v;
1738
1739 if (optlen != sizeof(u32))
1740 return -EINVAL;
1741 if (get_user(v, (u32 __user *)optval))
1742 return -EFAULT;
Dan Carpenter75356a82013-01-23 20:38:34 +00001743 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1744 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1745 return -EINVAL;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001746 if (sk == rcu_access_pointer(mrt->mroute_sk))
Patrick McHardyd1db2752010-05-11 14:40:55 +02001747 return -EBUSY;
1748
1749 rtnl_lock();
1750 ret = 0;
1751 if (!ip6mr_new_table(net, v))
1752 ret = -ENOMEM;
1753 raw6_sk(sk)->ip6mr_table = v;
1754 rtnl_unlock();
1755 return ret;
1756 }
1757#endif
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001758 /*
Rami Rosen7d120c52008-04-23 14:35:13 +03001759 * Spurious command, or MRT6_VERSION which you cannot
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001760 * set.
1761 */
1762 default:
1763 return -ENOPROTOOPT;
1764 }
1765}
1766
1767/*
1768 * Getsock opt support for the multicast routing system.
1769 */
1770
1771int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
1772 int __user *optlen)
1773{
1774 int olr;
1775 int val;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001776 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001777 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001778
Xin Long99253eb2017-02-24 16:29:06 +08001779 if (sk->sk_type != SOCK_RAW ||
1780 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1781 return -EOPNOTSUPP;
1782
Patrick McHardyd1db2752010-05-11 14:40:55 +02001783 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001784 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001785 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001786
1787 switch (optname) {
1788 case MRT6_VERSION:
1789 val = 0x0305;
1790 break;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001791#ifdef CONFIG_IPV6_PIMSM_V2
1792 case MRT6_PIM:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001793 val = mrt->mroute_do_pim;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001794 break;
1795#endif
1796 case MRT6_ASSERT:
Patrick McHardy6bd52142010-05-11 14:40:53 +02001797 val = mrt->mroute_do_assert;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001798 break;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001799 default:
1800 return -ENOPROTOOPT;
1801 }
1802
1803 if (get_user(olr, optlen))
1804 return -EFAULT;
1805
1806 olr = min_t(int, olr, sizeof(int));
1807 if (olr < 0)
1808 return -EINVAL;
1809
1810 if (put_user(olr, optlen))
1811 return -EFAULT;
1812 if (copy_to_user(optval, &val, olr))
1813 return -EFAULT;
1814 return 0;
1815}
1816
1817/*
1818 * The IP multicast ioctl support routines.
1819 */
1820
1821int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1822{
1823 struct sioc_sg_req6 sr;
1824 struct sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001825 struct vif_device *vif;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001826 struct mfc6_cache *c;
Benjamin Thery8229efd2008-12-10 16:30:15 -08001827 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001828 struct mr_table *mrt;
Patrick McHardyd1db2752010-05-11 14:40:55 +02001829
1830 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001831 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02001832 return -ENOENT;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001833
1834 switch (cmd) {
1835 case SIOCGETMIFCNT_IN6:
1836 if (copy_from_user(&vr, arg, sizeof(vr)))
1837 return -EFAULT;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001838 if (vr.mifi >= mrt->maxvif)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001839 return -EINVAL;
1840 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001841 vif = &mrt->vif_table[vr.mifi];
1842 if (VIF_EXISTS(mrt, vr.mifi)) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001843 vr.icount = vif->pkt_in;
1844 vr.ocount = vif->pkt_out;
1845 vr.ibytes = vif->bytes_in;
1846 vr.obytes = vif->bytes_out;
1847 read_unlock(&mrt_lock);
1848
1849 if (copy_to_user(arg, &vr, sizeof(vr)))
1850 return -EFAULT;
1851 return 0;
1852 }
1853 read_unlock(&mrt_lock);
1854 return -EADDRNOTAVAIL;
1855 case SIOCGETSGCNT_IN6:
1856 if (copy_from_user(&sr, arg, sizeof(sr)))
1857 return -EFAULT;
1858
Yuval Mintz87c418b2018-02-28 23:29:31 +02001859 rcu_read_lock();
Patrick McHardy6bd52142010-05-11 14:40:53 +02001860 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001861 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001862 sr.pktcnt = c->_c.mfc_un.res.pkt;
1863 sr.bytecnt = c->_c.mfc_un.res.bytes;
1864 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001865 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001866
1867 if (copy_to_user(arg, &sr, sizeof(sr)))
1868 return -EFAULT;
1869 return 0;
1870 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001871 rcu_read_unlock();
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001872 return -EADDRNOTAVAIL;
1873 default:
1874 return -ENOIOCTLCMD;
1875 }
1876}
1877
David S. Millere2d57762011-02-03 17:59:32 -08001878#ifdef CONFIG_COMPAT
1879struct compat_sioc_sg_req6 {
1880 struct sockaddr_in6 src;
1881 struct sockaddr_in6 grp;
1882 compat_ulong_t pktcnt;
1883 compat_ulong_t bytecnt;
1884 compat_ulong_t wrong_if;
1885};
1886
1887struct compat_sioc_mif_req6 {
1888 mifi_t mifi;
1889 compat_ulong_t icount;
1890 compat_ulong_t ocount;
1891 compat_ulong_t ibytes;
1892 compat_ulong_t obytes;
1893};
1894
1895int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1896{
1897 struct compat_sioc_sg_req6 sr;
1898 struct compat_sioc_mif_req6 vr;
Yuval Mintz6853f212018-02-28 23:29:29 +02001899 struct vif_device *vif;
David S. Millere2d57762011-02-03 17:59:32 -08001900 struct mfc6_cache *c;
1901 struct net *net = sock_net(sk);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001902 struct mr_table *mrt;
David S. Millere2d57762011-02-03 17:59:32 -08001903
1904 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01001905 if (!mrt)
David S. Millere2d57762011-02-03 17:59:32 -08001906 return -ENOENT;
1907
1908 switch (cmd) {
1909 case SIOCGETMIFCNT_IN6:
1910 if (copy_from_user(&vr, arg, sizeof(vr)))
1911 return -EFAULT;
1912 if (vr.mifi >= mrt->maxvif)
1913 return -EINVAL;
1914 read_lock(&mrt_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02001915 vif = &mrt->vif_table[vr.mifi];
1916 if (VIF_EXISTS(mrt, vr.mifi)) {
David S. Millere2d57762011-02-03 17:59:32 -08001917 vr.icount = vif->pkt_in;
1918 vr.ocount = vif->pkt_out;
1919 vr.ibytes = vif->bytes_in;
1920 vr.obytes = vif->bytes_out;
1921 read_unlock(&mrt_lock);
1922
1923 if (copy_to_user(arg, &vr, sizeof(vr)))
1924 return -EFAULT;
1925 return 0;
1926 }
1927 read_unlock(&mrt_lock);
1928 return -EADDRNOTAVAIL;
1929 case SIOCGETSGCNT_IN6:
1930 if (copy_from_user(&sr, arg, sizeof(sr)))
1931 return -EFAULT;
1932
Yuval Mintz87c418b2018-02-28 23:29:31 +02001933 rcu_read_lock();
David S. Millere2d57762011-02-03 17:59:32 -08001934 c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
1935 if (c) {
Yuval Mintz494fff52018-02-28 23:29:34 +02001936 sr.pktcnt = c->_c.mfc_un.res.pkt;
1937 sr.bytecnt = c->_c.mfc_un.res.bytes;
1938 sr.wrong_if = c->_c.mfc_un.res.wrong_if;
Yuval Mintz87c418b2018-02-28 23:29:31 +02001939 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001940
1941 if (copy_to_user(arg, &sr, sizeof(sr)))
1942 return -EFAULT;
1943 return 0;
1944 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02001945 rcu_read_unlock();
David S. Millere2d57762011-02-03 17:59:32 -08001946 return -EADDRNOTAVAIL;
1947 default:
1948 return -ENOIOCTLCMD;
1949 }
1950}
1951#endif
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001952
Eric W. Biederman0c4b51f2015-09-15 20:04:18 -05001953static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001954{
Eric Dumazet1d015502016-04-27 16:44:40 -07001955 __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
1956 IPSTATS_MIB_OUTFORWDATAGRAMS);
1957 __IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
1958 IPSTATS_MIB_OUTOCTETS, skb->len);
Eric W. Biederman13206b62015-10-07 16:48:35 -05001959 return dst_output(net, sk, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001960}
1961
1962/*
1963 * Processing handlers for ip6mr_forward
1964 */
1965
Yuval Mintzb70432f2018-02-28 23:29:32 +02001966static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
Patrick McHardy6bd52142010-05-11 14:40:53 +02001967 struct sk_buff *skb, struct mfc6_cache *c, int vifi)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001968{
1969 struct ipv6hdr *ipv6h;
Yuval Mintzb70432f2018-02-28 23:29:32 +02001970 struct vif_device *vif = &mrt->vif_table[vifi];
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001971 struct net_device *dev;
1972 struct dst_entry *dst;
David S. Miller4c9483b2011-03-12 16:22:43 -05001973 struct flowi6 fl6;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001974
Ian Morris63159f22015-03-29 14:00:04 +01001975 if (!vif->dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001976 goto out_free;
1977
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001978#ifdef CONFIG_IPV6_PIMSM_V2
1979 if (vif->flags & MIFF_REGISTER) {
1980 vif->pkt_out++;
1981 vif->bytes_out += skb->len;
Pavel Emelyanovdc58c782008-05-21 14:17:54 -07001982 vif->dev->stats.tx_bytes += skb->len;
1983 vif->dev->stats.tx_packets++;
Patrick McHardy6bd52142010-05-11 14:40:53 +02001984 ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
Ilpo Järvinen8da73b72008-12-14 23:15:49 -08001985 goto out_free;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09001986 }
1987#endif
1988
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001989 ipv6h = ipv6_hdr(skb);
1990
David S. Miller4c9483b2011-03-12 16:22:43 -05001991 fl6 = (struct flowi6) {
1992 .flowi6_oif = vif->link,
1993 .daddr = ipv6h->daddr,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001994 };
1995
David S. Miller4c9483b2011-03-12 16:22:43 -05001996 dst = ip6_route_output(net, NULL, &fl6);
RongQing.Li5095d642012-02-21 22:10:49 +00001997 if (dst->error) {
1998 dst_release(dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09001999 goto out_free;
RongQing.Li5095d642012-02-21 22:10:49 +00002000 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002001
Eric Dumazetadf30902009-06-02 05:19:30 +00002002 skb_dst_drop(skb);
2003 skb_dst_set(skb, dst);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002004
2005 /*
2006 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
2007 * not only before forwarding, but after forwarding on all output
2008 * interfaces. It is clear, if mrouter runs a multicasting
2009 * program, it should receive packets not depending to what interface
2010 * program is joined.
2011 * If we will not make it, the program will have to join on all
2012 * interfaces. On the other hand, multihoming host (or router, but
2013 * not mrouter) cannot join to more than one interface - it will
2014 * result in receiving multiple packets.
2015 */
2016 dev = vif->dev;
2017 skb->dev = dev;
2018 vif->pkt_out++;
2019 vif->bytes_out += skb->len;
2020
2021 /* We are about to write */
2022 /* XXX: extension headers? */
2023 if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
2024 goto out_free;
2025
2026 ipv6h = ipv6_hdr(skb);
2027 ipv6h->hop_limit--;
2028
2029 IP6CB(skb)->flags |= IP6SKB_FORWARDED;
2030
Eric W. Biederman29a26a52015-09-15 20:04:16 -05002031 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
2032 net, NULL, skb, skb->dev, dev,
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002033 ip6mr_forward2_finish);
2034
2035out_free:
2036 kfree_skb(skb);
2037 return 0;
2038}
2039
Yuval Mintzb70432f2018-02-28 23:29:32 +02002040static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002041{
2042 int ct;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002043
2044 for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
Yuval Mintzb70432f2018-02-28 23:29:32 +02002045 if (mrt->vif_table[ct].dev == dev)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002046 break;
2047 }
2048 return ct;
2049}
2050
Yuval Mintzb70432f2018-02-28 23:29:32 +02002051static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
Yuval Mintz494fff52018-02-28 23:29:34 +02002052 struct sk_buff *skb, struct mfc6_cache *c)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002053{
2054 int psend = -1;
2055 int vif, ct;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002056 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002057
Yuval Mintz494fff52018-02-28 23:29:34 +02002058 vif = c->_c.mfc_parent;
2059 c->_c.mfc_un.res.pkt++;
2060 c->_c.mfc_un.res.bytes += skb->len;
2061 c->_c.mfc_un.res.lastuse = jiffies;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002062
Yuval Mintz494fff52018-02-28 23:29:34 +02002063 if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002064 struct mfc6_cache *cache_proxy;
2065
Fabian Frederick40dc2ca2014-10-29 10:00:26 +01002066 /* For an (*,G) entry, we only check that the incoming
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002067 * interface is part of the static tree.
2068 */
Yuval Mintz87c418b2018-02-28 23:29:31 +02002069 rcu_read_lock();
Yuval Mintz845c9a72018-02-28 23:29:35 +02002070 cache_proxy = mr_mfc_find_any_parent(mrt, vif);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002071 if (cache_proxy &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002072 cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002073 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002074 goto forward;
Yuval Mintz87c418b2018-02-28 23:29:31 +02002075 }
2076 rcu_read_unlock();
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002077 }
2078
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002079 /*
2080 * Wrong interface: drop packet and (maybe) send PIM assert.
2081 */
Yuval Mintzb70432f2018-02-28 23:29:32 +02002082 if (mrt->vif_table[vif].dev != skb->dev) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002083 c->_c.mfc_un.res.wrong_if++;
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002084
Patrick McHardy6bd52142010-05-11 14:40:53 +02002085 if (true_vifi >= 0 && mrt->mroute_do_assert &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002086 /* pimsm uses asserts, when switching from RPT to SPT,
2087 so that we cannot check that packet arrived on an oif.
2088 It is bad, but otherwise we would need to move pretty
2089 large chunk of pimd to kernel. Ough... --ANK
2090 */
Patrick McHardy6bd52142010-05-11 14:40:53 +02002091 (mrt->mroute_do_pim ||
Yuval Mintz494fff52018-02-28 23:29:34 +02002092 c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002093 time_after(jiffies,
Yuval Mintz494fff52018-02-28 23:29:34 +02002094 c->_c.mfc_un.res.last_assert +
2095 MFC_ASSERT_THRESH)) {
2096 c->_c.mfc_un.res.last_assert = jiffies;
Patrick McHardy6bd52142010-05-11 14:40:53 +02002097 ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002098 }
2099 goto dont_forward;
2100 }
2101
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002102forward:
Yuval Mintzb70432f2018-02-28 23:29:32 +02002103 mrt->vif_table[vif].pkt_in++;
2104 mrt->vif_table[vif].bytes_in += skb->len;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002105
2106 /*
2107 * Forward the frame
2108 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002109 if (ipv6_addr_any(&c->mf6c_origin) &&
2110 ipv6_addr_any(&c->mf6c_mcastgrp)) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002111 if (true_vifi >= 0 &&
Yuval Mintz494fff52018-02-28 23:29:34 +02002112 true_vifi != c->_c.mfc_parent &&
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002113 ipv6_hdr(skb)->hop_limit >
Yuval Mintz494fff52018-02-28 23:29:34 +02002114 c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002115 /* It's an (*,*) entry and the packet is not coming from
2116 * the upstream: forward the packet to the upstream
2117 * only.
2118 */
Yuval Mintz494fff52018-02-28 23:29:34 +02002119 psend = c->_c.mfc_parent;
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002120 goto last_forward;
2121 }
2122 goto dont_forward;
2123 }
Yuval Mintz494fff52018-02-28 23:29:34 +02002124 for (ct = c->_c.mfc_un.res.maxvif - 1;
2125 ct >= c->_c.mfc_un.res.minvif; ct--) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002126 /* For (*,G) entry, don't forward to the incoming interface */
Yuval Mintz494fff52018-02-28 23:29:34 +02002127 if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
2128 ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002129 if (psend != -1) {
2130 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2131 if (skb2)
Yuval Mintz494fff52018-02-28 23:29:34 +02002132 ip6mr_forward2(net, mrt, skb2,
2133 c, psend);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002134 }
2135 psend = ct;
2136 }
2137 }
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002138last_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002139 if (psend != -1) {
Yuval Mintz494fff52018-02-28 23:29:34 +02002140 ip6mr_forward2(net, mrt, skb, c, psend);
Rami Rosen2b52c3a2013-07-21 03:00:31 +03002141 return;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002142 }
2143
YOSHIFUJI Hideaki14fb64e2008-04-03 09:22:54 +09002144dont_forward:
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002145 kfree_skb(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002146}
2147
2148
2149/*
2150 * Multicast packets for forwarding arrive here
2151 */
2152
2153int ip6_mr_input(struct sk_buff *skb)
2154{
2155 struct mfc6_cache *cache;
Benjamin Thery8229efd2008-12-10 16:30:15 -08002156 struct net *net = dev_net(skb->dev);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002157 struct mr_table *mrt;
David S. Miller4c9483b2011-03-12 16:22:43 -05002158 struct flowi6 fl6 = {
2159 .flowi6_iif = skb->dev->ifindex,
2160 .flowi6_mark = skb->mark,
Patrick McHardyd1db2752010-05-11 14:40:55 +02002161 };
2162 int err;
2163
David S. Miller4c9483b2011-03-12 16:22:43 -05002164 err = ip6mr_fib_lookup(net, &fl6, &mrt);
Ben Greear2015de52011-09-27 15:16:08 -04002165 if (err < 0) {
2166 kfree_skb(skb);
Patrick McHardyd1db2752010-05-11 14:40:55 +02002167 return err;
Ben Greear2015de52011-09-27 15:16:08 -04002168 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002169
2170 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002171 cache = ip6mr_cache_find(mrt,
Benjamin Thery8229efd2008-12-10 16:30:15 -08002172 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
Ian Morris63159f22015-03-29 14:00:04 +01002173 if (!cache) {
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002174 int vif = ip6mr_find_vif(mrt, skb->dev);
2175
2176 if (vif >= 0)
2177 cache = ip6mr_cache_find_any(mrt,
2178 &ipv6_hdr(skb)->daddr,
2179 vif);
2180 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002181
2182 /*
2183 * No usable cache entry
2184 */
Ian Morris63159f22015-03-29 14:00:04 +01002185 if (!cache) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002186 int vif;
2187
Patrick McHardy6bd52142010-05-11 14:40:53 +02002188 vif = ip6mr_find_vif(mrt, skb->dev);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002189 if (vif >= 0) {
Patrick McHardy6bd52142010-05-11 14:40:53 +02002190 int err = ip6mr_cache_unresolved(mrt, vif, skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002191 read_unlock(&mrt_lock);
2192
2193 return err;
2194 }
2195 read_unlock(&mrt_lock);
2196 kfree_skb(skb);
2197 return -ENODEV;
2198 }
2199
Patrick McHardy6bd52142010-05-11 14:40:53 +02002200 ip6_mr_forward(net, mrt, skb, cache);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002201
2202 read_unlock(&mrt_lock);
2203
2204 return 0;
2205}
2206
2207
Yuval Mintzb70432f2018-02-28 23:29:32 +02002208static int __ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002209 struct mfc6_cache *c, struct rtmsg *rtm)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002210{
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002211 struct rta_mfc_stats mfcs;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002212 struct nlattr *mp_attr;
2213 struct rtnexthop *nhp;
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002214 unsigned long lastuse;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002215 int ct;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002216
Nicolas Dichtel74381892010-03-25 23:45:35 +00002217 /* If cache is unresolved, don't try to parse IIF and OIF */
Yuval Mintz494fff52018-02-28 23:29:34 +02002218 if (c->_c.mfc_parent >= MAXMIFS) {
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002219 rtm->rtm_flags |= RTNH_F_UNRESOLVED;
Nicolas Dichtel74381892010-03-25 23:45:35 +00002220 return -ENOENT;
Nikolay Aleksandrov1708ebc2017-01-03 12:13:39 +01002221 }
Nicolas Dichtel74381892010-03-25 23:45:35 +00002222
Yuval Mintz494fff52018-02-28 23:29:34 +02002223 if (VIF_EXISTS(mrt, c->_c.mfc_parent) &&
Yuval Mintzb70432f2018-02-28 23:29:32 +02002224 nla_put_u32(skb, RTA_IIF,
Yuval Mintz494fff52018-02-28 23:29:34 +02002225 mrt->vif_table[c->_c.mfc_parent].dev->ifindex) < 0)
Thomas Graf74a0bd72012-06-26 23:36:14 +00002226 return -EMSGSIZE;
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002227 mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
Ian Morris63159f22015-03-29 14:00:04 +01002228 if (!mp_attr)
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002229 return -EMSGSIZE;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002230
Yuval Mintz494fff52018-02-28 23:29:34 +02002231 for (ct = c->_c.mfc_un.res.minvif;
2232 ct < c->_c.mfc_un.res.maxvif; ct++) {
2233 if (VIF_EXISTS(mrt, ct) && c->_c.mfc_un.res.ttls[ct] < 255) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002234 nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
Ian Morris63159f22015-03-29 14:00:04 +01002235 if (!nhp) {
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002236 nla_nest_cancel(skb, mp_attr);
2237 return -EMSGSIZE;
2238 }
2239
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002240 nhp->rtnh_flags = 0;
Yuval Mintz494fff52018-02-28 23:29:34 +02002241 nhp->rtnh_hops = c->_c.mfc_un.res.ttls[ct];
Yuval Mintzb70432f2018-02-28 23:29:32 +02002242 nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002243 nhp->rtnh_len = sizeof(*nhp);
2244 }
2245 }
Nicolas Dichtel70b386a2012-12-04 01:13:36 +00002246
2247 nla_nest_end(skb, mp_attr);
2248
Yuval Mintz494fff52018-02-28 23:29:34 +02002249 lastuse = READ_ONCE(c->_c.mfc_un.res.lastuse);
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002250 lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
2251
Yuval Mintz494fff52018-02-28 23:29:34 +02002252 mfcs.mfcs_packets = c->_c.mfc_un.res.pkt;
2253 mfcs.mfcs_bytes = c->_c.mfc_un.res.bytes;
2254 mfcs.mfcs_wrong_if = c->_c.mfc_un.res.wrong_if;
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002255 if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
Nikolay Aleksandrovb5036cd2016-09-20 16:17:22 +02002256 nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
Nikolay Aleksandrov43b9e122016-07-14 19:28:27 +03002257 RTA_PAD))
Nicolas Dichteladfa85e2012-12-04 01:13:37 +00002258 return -EMSGSIZE;
2259
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002260 rtm->rtm_type = RTN_MULTICAST;
2261 return 1;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002262}
2263
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002264int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
David Ahernfd61c6b2017-01-17 15:51:07 -08002265 u32 portid)
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002266{
2267 int err;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002268 struct mr_table *mrt;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002269 struct mfc6_cache *cache;
Eric Dumazetadf30902009-06-02 05:19:30 +00002270 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002271
Patrick McHardyd1db2752010-05-11 14:40:55 +02002272 mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
Ian Morris63159f22015-03-29 14:00:04 +01002273 if (!mrt)
Patrick McHardyd1db2752010-05-11 14:40:55 +02002274 return -ENOENT;
2275
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002276 read_lock(&mrt_lock);
Patrick McHardy6bd52142010-05-11 14:40:53 +02002277 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
Nicolas Dichtel660b26d2013-01-21 06:00:26 +00002278 if (!cache && skb->dev) {
2279 int vif = ip6mr_find_vif(mrt, skb->dev);
2280
2281 if (vif >= 0)
2282 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2283 vif);
2284 }
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002285
2286 if (!cache) {
2287 struct sk_buff *skb2;
2288 struct ipv6hdr *iph;
2289 struct net_device *dev;
2290 int vif;
2291
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002292 dev = skb->dev;
Ian Morris63159f22015-03-29 14:00:04 +01002293 if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002294 read_unlock(&mrt_lock);
2295 return -ENODEV;
2296 }
2297
2298 /* really correct? */
2299 skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
2300 if (!skb2) {
2301 read_unlock(&mrt_lock);
2302 return -ENOMEM;
2303 }
2304
Nikolay Aleksandrov2cf75072016-09-25 23:08:31 +02002305 NETLINK_CB(skb2).portid = portid;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002306 skb_reset_transport_header(skb2);
2307
2308 skb_put(skb2, sizeof(struct ipv6hdr));
2309 skb_reset_network_header(skb2);
2310
2311 iph = ipv6_hdr(skb2);
2312 iph->version = 0;
2313 iph->priority = 0;
2314 iph->flow_lbl[0] = 0;
2315 iph->flow_lbl[1] = 0;
2316 iph->flow_lbl[2] = 0;
2317 iph->payload_len = 0;
2318 iph->nexthdr = IPPROTO_NONE;
2319 iph->hop_limit = 0;
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +00002320 iph->saddr = rt->rt6i_src.addr;
2321 iph->daddr = rt->rt6i_dst.addr;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002322
Patrick McHardy6bd52142010-05-11 14:40:53 +02002323 err = ip6mr_cache_unresolved(mrt, vif, skb2);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002324 read_unlock(&mrt_lock);
2325
2326 return err;
2327 }
2328
David Ahernfd61c6b2017-01-17 15:51:07 -08002329 if (rtm->rtm_flags & RTM_F_NOTIFY)
Yuval Mintz494fff52018-02-28 23:29:34 +02002330 cache->_c.mfc_flags |= MFC_NOTIFY;
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002331
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002332 err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
YOSHIFUJI Hideaki7bc570c2008-04-03 09:22:53 +09002333 read_unlock(&mrt_lock);
2334 return err;
2335}
2336
Yuval Mintzb70432f2018-02-28 23:29:32 +02002337static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002338 u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
2339 int flags)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002340{
2341 struct nlmsghdr *nlh;
2342 struct rtmsg *rtm;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002343 int err;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002344
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002345 nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
Ian Morris63159f22015-03-29 14:00:04 +01002346 if (!nlh)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002347 return -EMSGSIZE;
2348
2349 rtm = nlmsg_data(nlh);
Nicolas Dichtel193c1e42012-12-04 01:01:49 +00002350 rtm->rtm_family = RTNL_FAMILY_IP6MR;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002351 rtm->rtm_dst_len = 128;
2352 rtm->rtm_src_len = 128;
2353 rtm->rtm_tos = 0;
2354 rtm->rtm_table = mrt->id;
David S. Millerc78679e2012-04-01 20:27:33 -04002355 if (nla_put_u32(skb, RTA_TABLE, mrt->id))
2356 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002357 rtm->rtm_type = RTN_MULTICAST;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002358 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
Yuval Mintz494fff52018-02-28 23:29:34 +02002359 if (c->_c.mfc_flags & MFC_STATIC)
Nicolas Dichtel9a68ac72012-12-04 01:13:38 +00002360 rtm->rtm_protocol = RTPROT_STATIC;
2361 else
2362 rtm->rtm_protocol = RTPROT_MROUTED;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002363 rtm->rtm_flags = 0;
2364
Jiri Benc930345e2015-03-29 16:59:25 +02002365 if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
2366 nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
David S. Millerc78679e2012-04-01 20:27:33 -04002367 goto nla_put_failure;
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002368 err = __ip6mr_fill_mroute(mrt, skb, c, rtm);
2369 /* do not break the dump if cache is unresolved */
2370 if (err < 0 && err != -ENOENT)
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002371 goto nla_put_failure;
2372
Johannes Berg053c0952015-01-16 22:09:00 +01002373 nlmsg_end(skb, nlh);
2374 return 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002375
2376nla_put_failure:
2377 nlmsg_cancel(skb, nlh);
2378 return -EMSGSIZE;
2379}
2380
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002381static int mr6_msgsize(bool unresolved, int maxvif)
2382{
2383 size_t len =
2384 NLMSG_ALIGN(sizeof(struct rtmsg))
2385 + nla_total_size(4) /* RTA_TABLE */
2386 + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */
2387 + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */
2388 ;
2389
2390 if (!unresolved)
2391 len = len
2392 + nla_total_size(4) /* RTA_IIF */
2393 + nla_total_size(0) /* RTA_MULTIPATH */
2394 + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
2395 /* RTA_MFC_STATS */
Nicolas Dichtel3d6b66c2016-04-21 18:58:27 +02002396 + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002397 ;
2398
2399 return len;
2400}
2401
Yuval Mintzb70432f2018-02-28 23:29:32 +02002402static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002403 int cmd)
2404{
2405 struct net *net = read_pnet(&mrt->net);
2406 struct sk_buff *skb;
2407 int err = -ENOBUFS;
2408
Yuval Mintz494fff52018-02-28 23:29:34 +02002409 skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002410 GFP_ATOMIC);
Ian Morris63159f22015-03-29 14:00:04 +01002411 if (!skb)
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002412 goto errout;
2413
Nicolas Dichtelf5183382014-03-19 17:47:51 +01002414 err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
Nicolas Dichtel812e44d2012-12-04 01:13:41 +00002415 if (err < 0)
2416 goto errout;
2417
2418 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
2419 return;
2420
2421errout:
2422 kfree_skb(skb);
2423 if (err < 0)
2424 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
2425}
2426
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002427static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
2428{
2429 size_t len =
2430 NLMSG_ALIGN(sizeof(struct rtgenmsg))
2431 + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */
2432 + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */
2433 /* IP6MRA_CREPORT_SRC_ADDR */
2434 + nla_total_size(sizeof(struct in6_addr))
2435 /* IP6MRA_CREPORT_DST_ADDR */
2436 + nla_total_size(sizeof(struct in6_addr))
2437 /* IP6MRA_CREPORT_PKT */
2438 + nla_total_size(payloadlen)
2439 ;
2440
2441 return len;
2442}
2443
Yuval Mintzb70432f2018-02-28 23:29:32 +02002444static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
Julien Gomesdd12d15c2017-06-20 13:54:18 -07002445{
2446 struct net *net = read_pnet(&mrt->net);
2447 struct nlmsghdr *nlh;
2448 struct rtgenmsg *rtgenm;
2449 struct mrt6msg *msg;
2450 struct sk_buff *skb;
2451 struct nlattr *nla;
2452 int payloadlen;
2453
2454 payloadlen = pkt->len - sizeof(struct mrt6msg);
2455 msg = (struct mrt6msg *)skb_transport_header(pkt);
2456
2457 skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
2458 if (!skb)
2459 goto errout;
2460
2461 nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
2462 sizeof(struct rtgenmsg), 0);
2463 if (!nlh)
2464 goto errout;
2465 rtgenm = nlmsg_data(nlh);
2466 rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
2467 if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
2468 nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
2469 nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
2470 &msg->im6_src) ||
2471 nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
2472 &msg->im6_dst))
2473 goto nla_put_failure;
2474
2475 nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
2476 if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
2477 nla_data(nla), payloadlen))
2478 goto nla_put_failure;
2479
2480 nlmsg_end(skb, nlh);
2481
2482 rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
2483 return;
2484
2485nla_put_failure:
2486 nlmsg_cancel(skb, nlh);
2487errout:
2488 kfree_skb(skb);
2489 rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
2490}
2491
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002492static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2493{
2494 struct net *net = sock_net(skb->sk);
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002495 unsigned int t = 0, s_t;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002496 unsigned int e = 0, s_e;
Yuval Mintz494fff52018-02-28 23:29:34 +02002497 struct mr_table *mrt;
2498 struct mr_mfc *mfc;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002499
2500 s_t = cb->args[0];
Yuval Mintz87c418b2018-02-28 23:29:31 +02002501 s_e = cb->args[1];
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002502
Yuval Mintz87c418b2018-02-28 23:29:31 +02002503 rcu_read_lock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002504 ip6mr_for_each_table(mrt, net) {
2505 if (t < s_t)
2506 goto next_table;
Yuval Mintzb70432f2018-02-28 23:29:32 +02002507 list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
Yuval Mintz87c418b2018-02-28 23:29:31 +02002508 if (e < s_e)
2509 goto next_entry;
2510 if (ip6mr_fill_mroute(mrt, skb,
2511 NETLINK_CB(cb->skb).portid,
2512 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002513 (struct mfc6_cache *)mfc,
2514 RTM_NEWROUTE, NLM_F_MULTI) < 0)
Yuval Mintz87c418b2018-02-28 23:29:31 +02002515 goto done;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002516next_entry:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002517 e++;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002518 }
Yuval Mintz87c418b2018-02-28 23:29:31 +02002519 e = 0;
2520 s_e = 0;
2521
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002522 spin_lock_bh(&mfc_unres_lock);
Yuval Mintzb70432f2018-02-28 23:29:32 +02002523 list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002524 if (e < s_e)
2525 goto next_entry2;
2526 if (ip6mr_fill_mroute(mrt, skb,
2527 NETLINK_CB(cb->skb).portid,
2528 cb->nlh->nlmsg_seq,
Yuval Mintz494fff52018-02-28 23:29:34 +02002529 (struct mfc6_cache *)mfc,
2530 RTM_NEWROUTE, NLM_F_MULTI) < 0) {
Nicolas Dichtel1eb99af2012-12-04 01:13:39 +00002531 spin_unlock_bh(&mfc_unres_lock);
2532 goto done;
2533 }
2534next_entry2:
2535 e++;
2536 }
2537 spin_unlock_bh(&mfc_unres_lock);
2538 e = s_e = 0;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002539next_table:
2540 t++;
2541 }
2542done:
Yuval Mintz87c418b2018-02-28 23:29:31 +02002543 rcu_read_unlock();
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002544
Yuval Mintz87c418b2018-02-28 23:29:31 +02002545 cb->args[1] = e;
Patrick McHardy5b285ca2010-05-11 14:40:56 +02002546 cb->args[0] = t;
2547
2548 return skb->len;
2549}