Blame view

net/ipv6/ip6mr.c 58.9 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2
3
4
5
6
7
8
9
10
11
  /*
   *	Linux IPv6 multicast routing support for BSD pim6sd
   *	Based on net/ipv4/ipmr.c.
   *
   *	(c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
   *		LSIIT Laboratory, Strasbourg, France
   *	(c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
   *		6WIND, Paris, France
   *	Copyright (C)2007,2008 USAGI/WIDE Project
   *		YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
12
   */
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
13
  #include <linux/uaccess.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
14
15
16
  #include <linux/types.h>
  #include <linux/sched.h>
  #include <linux/errno.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
17
18
19
20
21
  #include <linux/mm.h>
  #include <linux/kernel.h>
  #include <linux/fcntl.h>
  #include <linux/stat.h>
  #include <linux/socket.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
22
23
24
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/inetdevice.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
25
26
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
27
  #include <linux/init.h>
e2d57766e   David S. Miller   net: Provide comp...
28
  #include <linux/compat.h>
0eb71a9da   NeilBrown   rhashtable: split...
29
  #include <linux/rhashtable.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
30
31
  #include <net/protocol.h>
  #include <linux/skbuff.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
32
  #include <net/raw.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
33
34
  #include <linux/notifier.h>
  #include <linux/if_arp.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
35
36
  #include <net/checksum.h>
  #include <net/netlink.h>
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
37
  #include <net/fib_rules.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
38
39
40
41
  
  #include <net/ipv6.h>
  #include <net/ip6_route.h>
  #include <linux/mroute6.h>
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
42
  #include <linux/pim.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
43
44
  #include <net/addrconf.h>
  #include <linux/netfilter_ipv6.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
45
  #include <linux/export.h>
5d6e430d3   Dave Jones   ipv6: compile fix...
46
  #include <net/ip6_checksum.h>
d67b8c616   Nicolas Dichtel   netconf: advertis...
47
  #include <linux/netconf.h>
cb9f1b783   Willem de Bruijn   ip: validate head...
48
  #include <net/ip_tunnels.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
49

69d2c8676   Gustavo A. R. Silva   ip6mr: Fix potent...
50
  #include <linux/nospec.h>
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
51
52
53
54
55
  struct ip6mr_rule {
  	struct fib_rule		common;
  };
  
  struct ip6mr_result {
b70432f73   Yuval Mintz   mroute*: Make mr_...
56
  	struct mr_table	*mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
57
  };
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
58
59
60
61
62
  /* Big lock, protecting vif table, mrt cache and mroute socket state.
     Note that the changes are semaphored via rtnl_lock.
   */
  
  static DEFINE_RWLOCK(mrt_lock);
b70432f73   Yuval Mintz   mroute*: Make mr_...
63
  /* Multicast router control variables */
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
64

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
65
66
67
68
69
70
71
72
73
74
75
76
  /* Special spinlock for queue of unresolved entries */
  static DEFINE_SPINLOCK(mfc_unres_lock);
  
  /* We return to original Alan's scheme. Hash table of resolved
     entries is changed only in process context and protected
     with weak lock mrt_lock. Queue of unresolved entries is protected
     with strong spinlock mfc_unres_lock.
  
     In this case data path is free of exclusive locks at all.
   */
  
  static struct kmem_cache *mrt_cachep __read_mostly;
b70432f73   Yuval Mintz   mroute*: Make mr_...
77
78
  static struct mr_table *ip6mr_new_table(struct net *net, u32 id);
  static void ip6mr_free_table(struct mr_table *mrt);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
79

b70432f73   Yuval Mintz   mroute*: Make mr_...
80
  static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
81
82
  			   struct net_device *dev, struct sk_buff *skb,
  			   struct mfc6_cache *cache);
b70432f73   Yuval Mintz   mroute*: Make mr_...
83
  static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
8229efdae   Benjamin Thery   netns: ip6mr: ena...
84
  			      mifi_t mifi, int assert);
b70432f73   Yuval Mintz   mroute*: Make mr_...
85
  static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
86
  			      int cmd);
b70432f73   Yuval Mintz   mroute*: Make mr_...
87
  static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
88
89
  static int ip6mr_rtm_dumproute(struct sk_buff *skb,
  			       struct netlink_callback *cb);
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
90
  static void mroute_clean_tables(struct mr_table *mrt, int flags);
e99e88a9d   Kees Cook   treewide: setup_t...
91
  static void ipmr_expire_process(struct timer_list *t);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
92
93
  
  #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
8ffb335e8   Eric Dumazet   ip6mr: fix a typo...
94
  #define ip6mr_for_each_table(mrt, net) \
28b380e28   Amol Grover   ip6mr: Fix RCU li...
95
  	list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list, \
b6dd5acde   Madhuparna Bhowmik   ipv6: Fix suspici...
96
97
  				lockdep_rtnl_is_held() || \
  				list_empty(&net->ipv6.mr6_tables))
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
98

7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  static struct mr_table *ip6mr_mr_table_iter(struct net *net,
  					    struct mr_table *mrt)
  {
  	struct mr_table *ret;
  
  	if (!mrt)
  		ret = list_entry_rcu(net->ipv6.mr6_tables.next,
  				     struct mr_table, list);
  	else
  		ret = list_entry_rcu(mrt->list.next,
  				     struct mr_table, list);
  
  	if (&ret->list == &net->ipv6.mr6_tables)
  		return NULL;
  	return ret;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
115
  static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
116
  {
b70432f73   Yuval Mintz   mroute*: Make mr_...
117
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
118
119
120
121
122
123
124
  
  	ip6mr_for_each_table(mrt, net) {
  		if (mrt->id == id)
  			return mrt;
  	}
  	return NULL;
  }
4c9483b2f   David S. Miller   ipv6: Convert to ...
125
  static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
b70432f73   Yuval Mintz   mroute*: Make mr_...
126
  			    struct mr_table **mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
127
  {
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
128
  	int err;
95f4a45de   Hannes Frederic Sowa   net: avoid refere...
129
130
131
132
133
  	struct ip6mr_result res;
  	struct fib_lookup_arg arg = {
  		.result = &res,
  		.flags = FIB_LOOKUP_NOREF,
  	};
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
134

e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
135
136
  	/* update flow if oif or iif point to device enslaved to l3mdev */
  	l3mdev_update_flow(net, flowi6_to_flowi(flp6));
4c9483b2f   David S. Miller   ipv6: Convert to ...
137
138
  	err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
  			       flowi6_to_flowi(flp6), 0, &arg);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
139
140
141
142
143
144
145
146
147
148
  	if (err < 0)
  		return err;
  	*mrt = res.mrt;
  	return 0;
  }
  
  static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
  			     int flags, struct fib_lookup_arg *arg)
  {
  	struct ip6mr_result *res = arg->result;
b70432f73   Yuval Mintz   mroute*: Make mr_...
149
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
150
151
152
153
154
155
156
157
158
159
160
161
  
  	switch (rule->action) {
  	case FR_ACT_TO_TBL:
  		break;
  	case FR_ACT_UNREACHABLE:
  		return -ENETUNREACH;
  	case FR_ACT_PROHIBIT:
  		return -EACCES;
  	case FR_ACT_BLACKHOLE:
  	default:
  		return -EINVAL;
  	}
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
162
163
164
  	arg->table = fib_rule_get_table(rule, arg);
  
  	mrt = ip6mr_get_table(rule->fr_net, arg->table);
63159f29b   Ian Morris   ipv6: coding styl...
165
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  		return -EAGAIN;
  	res->mrt = mrt;
  	return 0;
  }
  
  static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
  {
  	return 1;
  }
  
  static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
  	FRA_GENERIC_POLICY,
  };
  
  static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
b16fb418b   Roopa Prabhu   net: fib_rules: a...
181
182
  				struct fib_rule_hdr *frh, struct nlattr **tb,
  				struct netlink_ext_ack *extack)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  {
  	return 0;
  }
  
  static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
  			      struct nlattr **tb)
  {
  	return 1;
  }
  
  static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
  			   struct fib_rule_hdr *frh)
  {
  	frh->dst_len = 0;
  	frh->src_len = 0;
  	frh->tos     = 0;
  	return 0;
  }
04a6f82cf   Andi Kleen   sections: fix sec...
201
  static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
202
203
204
205
206
207
208
  	.family		= RTNL_FAMILY_IP6MR,
  	.rule_size	= sizeof(struct ip6mr_rule),
  	.addr_size	= sizeof(struct in6_addr),
  	.action		= ip6mr_rule_action,
  	.match		= ip6mr_rule_match,
  	.configure	= ip6mr_rule_configure,
  	.compare	= ip6mr_rule_compare,
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
209
210
211
212
213
214
215
216
217
  	.fill		= ip6mr_rule_fill,
  	.nlgroup	= RTNLGRP_IPV6_RULE,
  	.policy		= ip6mr_rule_policy,
  	.owner		= THIS_MODULE,
  };
  
  static int __net_init ip6mr_rules_init(struct net *net)
  {
  	struct fib_rules_ops *ops;
b70432f73   Yuval Mintz   mroute*: Make mr_...
218
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
219
220
221
222
223
224
225
226
227
  	int err;
  
  	ops = fib_rules_register(&ip6mr_rules_ops_template, net);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  
  	INIT_LIST_HEAD(&net->ipv6.mr6_tables);
  
  	mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
e783bb00a   Sabrina Dubroca   ipmr: fix error p...
228
229
  	if (IS_ERR(mrt)) {
  		err = PTR_ERR(mrt);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
230
231
232
233
234
235
236
237
238
239
240
  		goto err1;
  	}
  
  	err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
  	if (err < 0)
  		goto err2;
  
  	net->ipv6.mr6_rules_ops = ops;
  	return 0;
  
  err2:
f243e5a78   WANG Cong   ipmr,ip6mr: call ...
241
  	ip6mr_free_table(mrt);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
242
243
244
245
246
247
248
  err1:
  	fib_rules_unregister(ops);
  	return err;
  }
  
  static void __net_exit ip6mr_rules_exit(struct net *net)
  {
b70432f73   Yuval Mintz   mroute*: Make mr_...
249
  	struct mr_table *mrt, *next;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
250

905a6f96a   Hannes Frederic Sowa   ipv6: take rtnl_l...
251
  	rtnl_lock();
035320d54   Eric Dumazet   ipmr: dont corrup...
252
253
  	list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
  		list_del(&mrt->list);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
254
  		ip6mr_free_table(mrt);
035320d54   Eric Dumazet   ipmr: dont corrup...
255
  	}
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
256
  	fib_rules_unregister(net->ipv6.mr6_rules_ops);
419df12fb   WANG Cong   net: move fib_rul...
257
  	rtnl_unlock();
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
258
  }
088aa3eec   Yuval Mintz   ip6mr: Support fi...
259

b7a595577   Jiri Pirko   net: fib_notifier...
260
261
  static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
  			    struct netlink_ext_ack *extack)
088aa3eec   Yuval Mintz   ip6mr: Support fi...
262
  {
b7a595577   Jiri Pirko   net: fib_notifier...
263
  	return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR, extack);
088aa3eec   Yuval Mintz   ip6mr: Support fi...
264
265
266
267
268
269
  }
  
  static unsigned int ip6mr_rules_seq_read(struct net *net)
  {
  	return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR);
  }
d3c07e5b9   Yuval Mintz   ip6mr: Add API fo...
270
271
272
273
274
275
276
  
  bool ip6mr_rule_default(const struct fib_rule *rule)
  {
  	return fib_rule_matchall(rule) && rule->action == FR_ACT_TO_TBL &&
  	       rule->table == RT6_TABLE_DFLT && !rule->l3mdev;
  }
  EXPORT_SYMBOL(ip6mr_rule_default);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
277
278
279
  #else
  #define ip6mr_for_each_table(mrt, net) \
  	for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
280
281
282
283
284
285
286
  static struct mr_table *ip6mr_mr_table_iter(struct net *net,
  					    struct mr_table *mrt)
  {
  	if (!mrt)
  		return net->ipv6.mrt6;
  	return NULL;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
287
  static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
288
289
290
  {
  	return net->ipv6.mrt6;
  }
4c9483b2f   David S. Miller   ipv6: Convert to ...
291
  static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
b70432f73   Yuval Mintz   mroute*: Make mr_...
292
  			    struct mr_table **mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
293
294
295
296
297
298
299
  {
  	*mrt = net->ipv6.mrt6;
  	return 0;
  }
  
  static int __net_init ip6mr_rules_init(struct net *net)
  {
e783bb00a   Sabrina Dubroca   ipmr: fix error p...
300
301
302
303
304
305
306
  	struct mr_table *mrt;
  
  	mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
  	if (IS_ERR(mrt))
  		return PTR_ERR(mrt);
  	net->ipv6.mrt6 = mrt;
  	return 0;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
307
308
309
310
  }
  
  static void __net_exit ip6mr_rules_exit(struct net *net)
  {
905a6f96a   Hannes Frederic Sowa   ipv6: take rtnl_l...
311
  	rtnl_lock();
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
312
  	ip6mr_free_table(net->ipv6.mrt6);
905a6f96a   Hannes Frederic Sowa   ipv6: take rtnl_l...
313
314
  	net->ipv6.mrt6 = NULL;
  	rtnl_unlock();
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
315
  }
088aa3eec   Yuval Mintz   ip6mr: Support fi...
316

b7a595577   Jiri Pirko   net: fib_notifier...
317
318
  static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
  			    struct netlink_ext_ack *extack)
088aa3eec   Yuval Mintz   ip6mr: Support fi...
319
320
321
322
323
324
325
326
  {
  	return 0;
  }
  
  static unsigned int ip6mr_rules_seq_read(struct net *net)
  {
  	return 0;
  }
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
327
  #endif
87c418bf1   Yuval Mintz   ip6mr: Align hash...
328
329
330
331
332
333
334
335
336
337
338
  static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg,
  			  const void *ptr)
  {
  	const struct mfc6_cache_cmp_arg *cmparg = arg->key;
  	struct mfc6_cache *c = (struct mfc6_cache *)ptr;
  
  	return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) ||
  	       !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin);
  }
  
  static const struct rhashtable_params ip6mr_rht_params = {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
339
  	.head_offset = offsetof(struct mr_mfc, mnode),
87c418bf1   Yuval Mintz   ip6mr: Align hash...
340
341
342
  	.key_offset = offsetof(struct mfc6_cache, cmparg),
  	.key_len = sizeof(struct mfc6_cache_cmp_arg),
  	.nelem_hint = 3,
87c418bf1   Yuval Mintz   ip6mr: Align hash...
343
344
345
  	.obj_cmpfn = ip6mr_hash_cmp,
  	.automatic_shrinking = true,
  };
0bbbf0e7d   Yuval Mintz   ipmr, ip6mr: Unit...
346
347
348
349
350
351
352
  static void ip6mr_new_table_set(struct mr_table *mrt,
  				struct net *net)
  {
  #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
  	list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
  #endif
  }
845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
353
354
355
356
357
358
359
360
361
  static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = {
  	.mf6c_origin = IN6ADDR_ANY_INIT,
  	.mf6c_mcastgrp = IN6ADDR_ANY_INIT,
  };
  
  static struct mr_table_ops ip6mr_mr_table_ops = {
  	.rht_params = &ip6mr_rht_params,
  	.cmparg_any = &ip6mr_mr_table_ops_cmparg_any,
  };
b70432f73   Yuval Mintz   mroute*: Make mr_...
362
  static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
363
  {
b70432f73   Yuval Mintz   mroute*: Make mr_...
364
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
365
366
  
  	mrt = ip6mr_get_table(net, id);
53b24b8f9   Ian Morris   ipv6: coding styl...
367
  	if (mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
368
  		return mrt;
845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
369
  	return mr_table_alloc(net, id, &ip6mr_mr_table_ops,
0bbbf0e7d   Yuval Mintz   ipmr, ip6mr: Unit...
370
  			      ipmr_expire_process, ip6mr_new_table_set);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
371
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
372

b70432f73   Yuval Mintz   mroute*: Make mr_...
373
  static void ip6mr_free_table(struct mr_table *mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
374
  {
7ba0c47c3   WANG Cong   ip6mr: call del_t...
375
  	del_timer_sync(&mrt->ipmr_expire_timer);
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
376
377
  	mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC |
  				 MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC);
b70432f73   Yuval Mintz   mroute*: Make mr_...
378
  	rhltable_destroy(&mrt->mfc_hash);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
379
380
  	kfree(mrt);
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
381
382
  
  #ifdef CONFIG_PROC_FS
c8d619680   Yuval Mintz   ipmr, ip6mr: Unit...
383
384
  /* The /proc interfaces to multicast routing
   * /proc/ip6_mr_cache /proc/ip6_mr_vif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
385
   */
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
386
387
388
  static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
  	__acquires(mrt_lock)
  {
3feda6b46   Yuval Mintz   ipmr, ip6mr: Unit...
389
  	struct mr_vif_iter *iter = seq->private;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
390
  	struct net *net = seq_file_net(seq);
b70432f73   Yuval Mintz   mroute*: Make mr_...
391
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
392
393
  
  	mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
394
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
395
396
397
  		return ERR_PTR(-ENOENT);
  
  	iter->mrt = mrt;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
398

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
399
  	read_lock(&mrt_lock);
3feda6b46   Yuval Mintz   ipmr, ip6mr: Unit...
400
  	return mr_vif_seq_start(seq, pos);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
401
402
403
404
405
406
407
408
409
410
  }
  
  static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
  	__releases(mrt_lock)
  {
  	read_unlock(&mrt_lock);
  }
  
  static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
  {
3feda6b46   Yuval Mintz   ipmr, ip6mr: Unit...
411
  	struct mr_vif_iter *iter = seq->private;
b70432f73   Yuval Mintz   mroute*: Make mr_...
412
  	struct mr_table *mrt = iter->mrt;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
413

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
414
415
416
417
418
  	if (v == SEQ_START_TOKEN) {
  		seq_puts(seq,
  			 "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags
  ");
  	} else {
6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
419
  		const struct vif_device *vif = v;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
420
421
422
  		const char *name = vif->dev ? vif->dev->name : "none";
  
  		seq_printf(seq,
d430a227d   Al Viro   bogus format in i...
423
424
  			   "%2td %-10s %8ld %7ld  %8ld %7ld %05X
  ",
b70432f73   Yuval Mintz   mroute*: Make mr_...
425
  			   vif - mrt->vif_table,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
426
427
428
429
430
431
  			   name, vif->bytes_in, vif->pkt_in,
  			   vif->bytes_out, vif->pkt_out,
  			   vif->flags);
  	}
  	return 0;
  }
98147d527   Stephen Hemminger   net: seq_operatio...
432
  static const struct seq_operations ip6mr_vif_seq_ops = {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
433
  	.start = ip6mr_vif_seq_start,
3feda6b46   Yuval Mintz   ipmr, ip6mr: Unit...
434
  	.next  = mr_vif_seq_next,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
435
436
437
  	.stop  = ip6mr_vif_seq_stop,
  	.show  = ip6mr_vif_seq_show,
  };
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
438
439
  static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
  {
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
440
  	struct net *net = seq_file_net(seq);
b70432f73   Yuval Mintz   mroute*: Make mr_...
441
  	struct mr_table *mrt;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
442

d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
443
  	mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
444
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
445
  		return ERR_PTR(-ENOENT);
c8d619680   Yuval Mintz   ipmr, ip6mr: Unit...
446
  	return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
  }
  
  static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
  {
  	int n;
  
  	if (v == SEQ_START_TOKEN) {
  		seq_puts(seq,
  			 "Group                            "
  			 "Origin                           "
  			 "Iif      Pkts  Bytes     Wrong  Oifs
  ");
  	} else {
  		const struct mfc6_cache *mfc = v;
c8d619680   Yuval Mintz   ipmr, ip6mr: Unit...
461
  		const struct mr_mfc_iter *it = seq->private;
b70432f73   Yuval Mintz   mroute*: Make mr_...
462
  		struct mr_table *mrt = it->mrt;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
463

999890b21   Benjamin Thery   net: /proc/net/ip...
464
  		seq_printf(seq, "%pI6 %pI6 %-3hd",
0c6ce78ab   Harvey Harrison   net: replace uses...
465
  			   &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
466
  			   mfc->_c.mfc_parent);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
467

b70432f73   Yuval Mintz   mroute*: Make mr_...
468
  		if (it->cache != &mrt->mfc_unres_queue) {
1ea472e2d   Benjamin Thery   net: fix /proc/ne...
469
  			seq_printf(seq, " %8lu %8lu %8lu",
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
470
471
472
473
474
  				   mfc->_c.mfc_un.res.pkt,
  				   mfc->_c.mfc_un.res.bytes,
  				   mfc->_c.mfc_un.res.wrong_if);
  			for (n = mfc->_c.mfc_un.res.minvif;
  			     n < mfc->_c.mfc_un.res.maxvif; n++) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
475
  				if (VIF_EXISTS(mrt, n) &&
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
476
  				    mfc->_c.mfc_un.res.ttls[n] < 255)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
477
  					seq_printf(seq,
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
478
479
  						   " %2d:%-3d", n,
  						   mfc->_c.mfc_un.res.ttls[n]);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
480
  			}
1ea472e2d   Benjamin Thery   net: fix /proc/ne...
481
482
483
484
485
  		} else {
  			/* unresolved mfc_caches don't contain
  			 * pkt, bytes and wrong_if values
  			 */
  			seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
486
487
488
489
490
491
  		}
  		seq_putc(seq, '
  ');
  	}
  	return 0;
  }
88e9d34c7   James Morris   seq_file: constif...
492
  static const struct seq_operations ipmr_mfc_seq_ops = {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
493
  	.start = ipmr_mfc_seq_start,
c8d619680   Yuval Mintz   ipmr, ip6mr: Unit...
494
495
  	.next  = mr_mfc_seq_next,
  	.stop  = mr_mfc_seq_stop,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
496
497
  	.show  = ipmr_mfc_seq_show,
  };
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
498
  #endif
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
499
  #ifdef CONFIG_IPV6_PIMSM_V2
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
500
501
502
503
504
505
  
  static int pim6_rcv(struct sk_buff *skb)
  {
  	struct pimreghdr *pim;
  	struct ipv6hdr   *encap;
  	struct net_device  *reg_dev = NULL;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
506
  	struct net *net = dev_net(skb->dev);
b70432f73   Yuval Mintz   mroute*: Make mr_...
507
  	struct mr_table *mrt;
4c9483b2f   David S. Miller   ipv6: Convert to ...
508
509
510
  	struct flowi6 fl6 = {
  		.flowi6_iif	= skb->dev->ifindex,
  		.flowi6_mark	= skb->mark,
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
511
512
  	};
  	int reg_vif_num;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
513
514
515
516
517
  
  	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
  		goto drop;
  
  	pim = (struct pimreghdr *)skb_transport_header(skb);
56245cae1   Nikolay Aleksandrov   net: pim: add all...
518
  	if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) ||
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
519
  	    (pim->flags & PIM_NULL_REGISTER) ||
1d6e55f19   Thomas Goff   IPv6: Fix multica...
520
521
522
  	    (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
  			     sizeof(*pim), IPPROTO_PIM,
  			     csum_partial((void *)pim, sizeof(*pim), 0)) &&
ec6b486fa   Al Viro   ipv6: result of c...
523
  	     csum_fold(skb_checksum(skb, 0, skb->len, 0))))
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
524
525
526
527
528
529
530
531
532
533
  		goto drop;
  
  	/* check if the inner packet is destined to mcast group */
  	encap = (struct ipv6hdr *)(skb_transport_header(skb) +
  				   sizeof(*pim));
  
  	if (!ipv6_addr_is_multicast(&encap->daddr) ||
  	    encap->payload_len == 0 ||
  	    ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
  		goto drop;
4c9483b2f   David S. Miller   ipv6: Convert to ...
534
  	if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
535
536
  		goto drop;
  	reg_vif_num = mrt->mroute_reg_vif_num;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
537
538
  	read_lock(&mrt_lock);
  	if (reg_vif_num >= 0)
b70432f73   Yuval Mintz   mroute*: Make mr_...
539
  		reg_dev = mrt->vif_table[reg_vif_num].dev;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
540
541
542
  	if (reg_dev)
  		dev_hold(reg_dev);
  	read_unlock(&mrt_lock);
63159f29b   Ian Morris   ipv6: coding styl...
543
  	if (!reg_dev)
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
544
545
546
547
548
  		goto drop;
  
  	skb->mac_header = skb->network_header;
  	skb_pull(skb, (u8 *)encap - skb->data);
  	skb_reset_network_header(skb);
1d6e55f19   Thomas Goff   IPv6: Fix multica...
549
  	skb->protocol = htons(ETH_P_IPV6);
3e49e6d52   Cesar Eduardo Barros   net: use CHECKSUM...
550
  	skb->ip_summed = CHECKSUM_NONE;
d19d56ddc   Eric Dumazet   net: Introduce sk...
551

ea23192e8   Nicolas Dichtel   tunnels: harmoniz...
552
  	skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
d19d56ddc   Eric Dumazet   net: Introduce sk...
553

caf586e5f   Eric Dumazet   net: add a core n...
554
  	netif_rx(skb);
8990f468a   Eric Dumazet   net: rx_dropped a...
555

14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
556
557
558
559
560
561
  	dev_put(reg_dev);
  	return 0;
   drop:
  	kfree_skb(skb);
  	return 0;
  }
41135cc83   Alexey Dobriyan   net: constify str...
562
  static const struct inet6_protocol pim6_protocol = {
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
563
564
565
566
  	.handler	=	pim6_rcv,
  };
  
  /* Service routines creating virtual interfaces: PIMREG */
6fef4c0c8   Stephen Hemminger   netdev: convert p...
567
568
  static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
  				      struct net_device *dev)
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
569
  {
8229efdae   Benjamin Thery   netns: ip6mr: ena...
570
  	struct net *net = dev_net(dev);
b70432f73   Yuval Mintz   mroute*: Make mr_...
571
  	struct mr_table *mrt;
4c9483b2f   David S. Miller   ipv6: Convert to ...
572
573
  	struct flowi6 fl6 = {
  		.flowi6_oif	= dev->ifindex,
6a662719c   Cong Wang   ipv4, fib: pass L...
574
  		.flowi6_iif	= skb->skb_iif ? : LOOPBACK_IFINDEX,
4c9483b2f   David S. Miller   ipv6: Convert to ...
575
  		.flowi6_mark	= skb->mark,
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
576
  	};
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
577

cb9f1b783   Willem de Bruijn   ip: validate head...
578
579
580
581
582
  	if (!pskb_inet_may_pull(skb))
  		goto tx_err;
  
  	if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
  		goto tx_err;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
583

14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
584
  	read_lock(&mrt_lock);
dc58c78c0   Pavel Emelyanov   ip6mr: Use on-dev...
585
586
  	dev->stats.tx_bytes += skb->len;
  	dev->stats.tx_packets++;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
587
  	ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
588
589
  	read_unlock(&mrt_lock);
  	kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
590
  	return NETDEV_TX_OK;
cb9f1b783   Willem de Bruijn   ip: validate head...
591
592
593
594
595
  
  tx_err:
  	dev->stats.tx_errors++;
  	kfree_skb(skb);
  	return NETDEV_TX_OK;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
596
  }
ee9b9596a   Nicolas Dichtel   ipmr,ip6mr: imple...
597
598
599
600
  static int reg_vif_get_iflink(const struct net_device *dev)
  {
  	return 0;
  }
007c3838d   Stephen Hemminger   ipmr: convert ipm...
601
602
  static const struct net_device_ops reg_vif_netdev_ops = {
  	.ndo_start_xmit	= reg_vif_xmit,
ee9b9596a   Nicolas Dichtel   ipmr,ip6mr: imple...
603
  	.ndo_get_iflink = reg_vif_get_iflink,
007c3838d   Stephen Hemminger   ipmr: convert ipm...
604
  };
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
605
606
607
608
609
  static void reg_vif_setup(struct net_device *dev)
  {
  	dev->type		= ARPHRD_PIMREG;
  	dev->mtu		= 1500 - sizeof(struct ipv6hdr) - 8;
  	dev->flags		= IFF_NOARP;
007c3838d   Stephen Hemminger   ipmr: convert ipm...
610
  	dev->netdev_ops		= &reg_vif_netdev_ops;
cf124db56   David S. Miller   net: Fix inconsis...
611
  	dev->needs_free_netdev	= true;
403dbb97f   Tom Goff   PIM-SM: namespace...
612
  	dev->features		|= NETIF_F_NETNS_LOCAL;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
613
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
614
  static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt)
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
615
616
  {
  	struct net_device *dev;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
617
618
619
620
621
622
  	char name[IFNAMSIZ];
  
  	if (mrt->id == RT6_TABLE_DFLT)
  		sprintf(name, "pim6reg");
  	else
  		sprintf(name, "pim6reg%u", mrt->id);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
623

c835a6773   Tom Gundersen   net: set name_ass...
624
  	dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);
63159f29b   Ian Morris   ipv6: coding styl...
625
  	if (!dev)
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
626
  		return NULL;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
627
  	dev_net_set(dev, net);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
628
629
630
631
  	if (register_netdevice(dev)) {
  		free_netdev(dev);
  		return NULL;
  	}
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
632

00f54e689   Petr Machata   net: core: dev: A...
633
  	if (dev_open(dev, NULL))
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
634
  		goto failure;
7af3db78a   Wang Chen   ipv6: Fix using a...
635
  	dev_hold(dev);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
636
637
638
  	return dev;
  
  failure:
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
639
640
641
642
  	unregister_netdevice(dev);
  	return NULL;
  }
  #endif
088aa3eec   Yuval Mintz   ip6mr: Support fi...
643
644
645
646
647
648
649
650
651
  static int call_ip6mr_vif_entry_notifiers(struct net *net,
  					  enum fib_event_type event_type,
  					  struct vif_device *vif,
  					  mifi_t vif_index, u32 tb_id)
  {
  	return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
  				     vif, vif_index, tb_id,
  				     &net->ipv6.ipmr_seq);
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
652

088aa3eec   Yuval Mintz   ip6mr: Support fi...
653
654
655
656
657
658
659
660
661
  static int call_ip6mr_mfc_entry_notifiers(struct net *net,
  					  enum fib_event_type event_type,
  					  struct mfc6_cache *mfc, u32 tb_id)
  {
  	return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
  				     &mfc->_c, tb_id, &net->ipv6.ipmr_seq);
  }
  
  /* Delete a VIF entry */
b70432f73   Yuval Mintz   mroute*: Make mr_...
662
  static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
723b929ca   Nikolay Aleksandrov   ip6mr: fix notifi...
663
  		       struct list_head *head)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
664
  {
6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
665
  	struct vif_device *v;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
666
  	struct net_device *dev;
1d6e55f19   Thomas Goff   IPv6: Fix multica...
667
  	struct inet6_dev *in6_dev;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
668
669
  
  	if (vifi < 0 || vifi >= mrt->maxvif)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
670
  		return -EADDRNOTAVAIL;
b70432f73   Yuval Mintz   mroute*: Make mr_...
671
  	v = &mrt->vif_table[vifi];
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
672

088aa3eec   Yuval Mintz   ip6mr: Support fi...
673
674
675
676
  	if (VIF_EXISTS(mrt, vifi))
  		call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
  					       FIB_EVENT_VIF_DEL, v, vifi,
  					       mrt->id);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
677
678
679
680
681
682
683
684
  	write_lock_bh(&mrt_lock);
  	dev = v->dev;
  	v->dev = NULL;
  
  	if (!dev) {
  		write_unlock_bh(&mrt_lock);
  		return -EADDRNOTAVAIL;
  	}
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
685
  #ifdef CONFIG_IPV6_PIMSM_V2
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
686
687
  	if (vifi == mrt->mroute_reg_vif_num)
  		mrt->mroute_reg_vif_num = -1;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
688
  #endif
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
689
  	if (vifi + 1 == mrt->maxvif) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
690
691
  		int tmp;
  		for (tmp = vifi - 1; tmp >= 0; tmp--) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
692
  			if (VIF_EXISTS(mrt, tmp))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
693
694
  				break;
  		}
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
695
  		mrt->maxvif = tmp + 1;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
696
697
698
699
700
  	}
  
  	write_unlock_bh(&mrt_lock);
  
  	dev_set_allmulti(dev, -1);
1d6e55f19   Thomas Goff   IPv6: Fix multica...
701
  	in6_dev = __in6_dev_get(dev);
d67b8c616   Nicolas Dichtel   netconf: advertis...
702
  	if (in6_dev) {
1d6e55f19   Thomas Goff   IPv6: Fix multica...
703
  		in6_dev->cnf.mc_forwarding--;
85b3daada   David Ahern   net: ipv6: Refact...
704
  		inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
d67b8c616   Nicolas Dichtel   netconf: advertis...
705
706
707
  					     NETCONFA_MC_FORWARDING,
  					     dev->ifindex, &in6_dev->cnf);
  	}
1d6e55f19   Thomas Goff   IPv6: Fix multica...
708

723b929ca   Nikolay Aleksandrov   ip6mr: fix notifi...
709
  	if ((v->flags & MIFF_REGISTER) && !notify)
c871e664e   Eric Dumazet   ip6mr: Optimize m...
710
  		unregister_netdevice_queue(dev, head);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
711
712
713
714
  
  	dev_put(dev);
  	return 0;
  }
87c418bf1   Yuval Mintz   ip6mr: Align hash...
715
  static inline void ip6mr_cache_free_rcu(struct rcu_head *head)
58701ad41   Benjamin Thery   netns: ip6mr: sto...
716
  {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
717
  	struct mr_mfc *c = container_of(head, struct mr_mfc, rcu);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
718

494fff563   Yuval Mintz   ipmr, ip6mr: Make...
719
  	kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c);
58701ad41   Benjamin Thery   netns: ip6mr: sto...
720
  }
87c418bf1   Yuval Mintz   ip6mr: Align hash...
721
722
  static inline void ip6mr_cache_free(struct mfc6_cache *c)
  {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
723
  	call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
724
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
725
726
727
  /* Destroy an unresolved cache entry, killing queued skbs
     and reporting error to netlink readers.
   */
b70432f73   Yuval Mintz   mroute*: Make mr_...
728
  static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
729
  {
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
730
  	struct net *net = read_pnet(&mrt->net);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
731
  	struct sk_buff *skb;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
732
  	atomic_dec(&mrt->cache_resolve_queue_len);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
733

494fff563   Yuval Mintz   ipmr, ip6mr: Make...
734
  	while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
735
  		if (ipv6_hdr(skb)->version == 0) {
af72868b9   Johannes Berg   networking: make ...
736
737
  			struct nlmsghdr *nlh = skb_pull(skb,
  							sizeof(struct ipv6hdr));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
738
  			nlh->nlmsg_type = NLMSG_ERROR;
573ce260b   Hong zhi guo   net-next: replace...
739
  			nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
740
  			skb_trim(skb, nlh->nlmsg_len);
573ce260b   Hong zhi guo   net-next: replace...
741
  			((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
15e473046   Eric W. Biederman   netlink: Rename p...
742
  			rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
743
744
745
  		} else
  			kfree_skb(skb);
  	}
58701ad41   Benjamin Thery   netns: ip6mr: sto...
746
  	ip6mr_cache_free(c);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
747
  }
c476efbcd   Patrick McHardy   ipv6: ip6mr: move...
748
  /* Timer process for all the unresolved queue. */
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
749

b70432f73   Yuval Mintz   mroute*: Make mr_...
750
  static void ipmr_do_expire_process(struct mr_table *mrt)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
751
752
753
  {
  	unsigned long now = jiffies;
  	unsigned long expires = 10 * HZ;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
754
  	struct mr_mfc *c, *next;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
755

b70432f73   Yuval Mintz   mroute*: Make mr_...
756
  	list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
757
758
759
760
761
  		if (time_after(c->mfc_un.unres.expires, now)) {
  			/* not yet... */
  			unsigned long interval = c->mfc_un.unres.expires - now;
  			if (interval < expires)
  				expires = interval;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
762
763
  			continue;
  		}
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
764
  		list_del(&c->list);
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
765
766
  		mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
  		ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
767
  	}
b70432f73   Yuval Mintz   mroute*: Make mr_...
768
  	if (!list_empty(&mrt->mfc_unres_queue))
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
769
  		mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
770
  }
e99e88a9d   Kees Cook   treewide: setup_t...
771
  static void ipmr_expire_process(struct timer_list *t)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
772
  {
b70432f73   Yuval Mintz   mroute*: Make mr_...
773
  	struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer);
c476efbcd   Patrick McHardy   ipv6: ip6mr: move...
774

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
775
  	if (!spin_trylock(&mfc_unres_lock)) {
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
776
  		mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
777
778
  		return;
  	}
b70432f73   Yuval Mintz   mroute*: Make mr_...
779
  	if (!list_empty(&mrt->mfc_unres_queue))
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
780
  		ipmr_do_expire_process(mrt);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
781
782
783
784
785
  
  	spin_unlock(&mfc_unres_lock);
  }
  
  /* Fill oifs list. It is called under write locked mrt_lock. */
b70432f73   Yuval Mintz   mroute*: Make mr_...
786
  static void ip6mr_update_thresholds(struct mr_table *mrt,
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
787
  				    struct mr_mfc *cache,
b5aa30b19   Patrick McHardy   ipv6: ip6mr: remo...
788
  				    unsigned char *ttls)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
789
790
  {
  	int vifi;
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
791
  	cache->mfc_un.res.minvif = MAXMIFS;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
792
  	cache->mfc_un.res.maxvif = 0;
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
793
  	memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
794

6bd521433   Patrick McHardy   ipv6: ip6mr: move...
795
  	for (vifi = 0; vifi < mrt->maxvif; vifi++) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
796
  		if (VIF_EXISTS(mrt, vifi) &&
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
797
  		    ttls[vifi] && ttls[vifi] < 255) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
798
799
800
801
802
803
804
  			cache->mfc_un.res.ttls[vifi] = ttls[vifi];
  			if (cache->mfc_un.res.minvif > vifi)
  				cache->mfc_un.res.minvif = vifi;
  			if (cache->mfc_un.res.maxvif <= vifi)
  				cache->mfc_un.res.maxvif = vifi + 1;
  		}
  	}
90b5ca176   Nikolay Aleksandrov   net: ipmr/ip6mr: ...
805
  	cache->mfc_un.res.lastuse = jiffies;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
806
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
807
  static int mif6_add(struct net *net, struct mr_table *mrt,
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
808
  		    struct mif6ctl *vifc, int mrtsock)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
809
810
  {
  	int vifi = vifc->mif6c_mifi;
b70432f73   Yuval Mintz   mroute*: Make mr_...
811
  	struct vif_device *v = &mrt->vif_table[vifi];
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
812
  	struct net_device *dev;
1d6e55f19   Thomas Goff   IPv6: Fix multica...
813
  	struct inet6_dev *in6_dev;
5ae7b4441   Wang Chen   ipv6: Check retur...
814
  	int err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
815
816
  
  	/* Is vif busy ? */
b70432f73   Yuval Mintz   mroute*: Make mr_...
817
  	if (VIF_EXISTS(mrt, vifi))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
818
819
820
  		return -EADDRINUSE;
  
  	switch (vifc->mif6c_flags) {
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
821
822
823
824
825
826
  #ifdef CONFIG_IPV6_PIMSM_V2
  	case MIFF_REGISTER:
  		/*
  		 * Special Purpose VIF in PIM
  		 * All the packets will be sent to the daemon
  		 */
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
827
  		if (mrt->mroute_reg_vif_num >= 0)
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
828
  			return -EADDRINUSE;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
829
  		dev = ip6mr_reg_vif(net, mrt);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
830
831
  		if (!dev)
  			return -ENOBUFS;
5ae7b4441   Wang Chen   ipv6: Check retur...
832
833
834
  		err = dev_set_allmulti(dev, 1);
  		if (err) {
  			unregister_netdevice(dev);
7af3db78a   Wang Chen   ipv6: Fix using a...
835
  			dev_put(dev);
5ae7b4441   Wang Chen   ipv6: Check retur...
836
837
  			return err;
  		}
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
838
839
  		break;
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
840
  	case 0:
8229efdae   Benjamin Thery   netns: ip6mr: ena...
841
  		dev = dev_get_by_index(net, vifc->mif6c_pifi);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
842
843
  		if (!dev)
  			return -EADDRNOTAVAIL;
5ae7b4441   Wang Chen   ipv6: Check retur...
844
  		err = dev_set_allmulti(dev, 1);
7af3db78a   Wang Chen   ipv6: Fix using a...
845
846
  		if (err) {
  			dev_put(dev);
5ae7b4441   Wang Chen   ipv6: Check retur...
847
  			return err;
7af3db78a   Wang Chen   ipv6: Fix using a...
848
  		}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
849
850
851
852
  		break;
  	default:
  		return -EINVAL;
  	}
1d6e55f19   Thomas Goff   IPv6: Fix multica...
853
  	in6_dev = __in6_dev_get(dev);
d67b8c616   Nicolas Dichtel   netconf: advertis...
854
  	if (in6_dev) {
1d6e55f19   Thomas Goff   IPv6: Fix multica...
855
  		in6_dev->cnf.mc_forwarding++;
85b3daada   David Ahern   net: ipv6: Refact...
856
  		inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF,
d67b8c616   Nicolas Dichtel   netconf: advertis...
857
858
859
  					     NETCONFA_MC_FORWARDING,
  					     dev->ifindex, &in6_dev->cnf);
  	}
1d6e55f19   Thomas Goff   IPv6: Fix multica...
860

6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
861
862
863
864
  	/* Fill in the VIF structures */
  	vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold,
  			vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0),
  			MIFF_REGISTER);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
865
866
867
  
  	/* And finish update writing critical data */
  	write_lock_bh(&mrt_lock);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
868
  	v->dev = dev;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
869
870
  #ifdef CONFIG_IPV6_PIMSM_V2
  	if (v->flags & MIFF_REGISTER)
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
871
  		mrt->mroute_reg_vif_num = vifi;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
872
  #endif
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
873
874
  	if (vifi + 1 > mrt->maxvif)
  		mrt->maxvif = vifi + 1;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
875
  	write_unlock_bh(&mrt_lock);
088aa3eec   Yuval Mintz   ip6mr: Support fi...
876
877
  	call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
  				       v, vifi, mrt->id);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
878
879
  	return 0;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
880
  static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt,
b71d1d426   Eric Dumazet   inet: constify ip...
881
882
  					   const struct in6_addr *origin,
  					   const struct in6_addr *mcastgrp)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
883
  {
87c418bf1   Yuval Mintz   ip6mr: Align hash...
884
885
886
887
  	struct mfc6_cache_cmp_arg arg = {
  		.mf6c_origin = *origin,
  		.mf6c_mcastgrp = *mcastgrp,
  	};
87c418bf1   Yuval Mintz   ip6mr: Align hash...
888

845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
889
  	return mr_mfc_find(mrt, &arg);
660b26dc1   Nicolas Dichtel   mcast: add multic...
890
891
892
  }
  
  /* Look for a (*,G) entry */
b70432f73   Yuval Mintz   mroute*: Make mr_...
893
  static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt,
660b26dc1   Nicolas Dichtel   mcast: add multic...
894
895
896
  					       struct in6_addr *mcastgrp,
  					       mifi_t mifi)
  {
87c418bf1   Yuval Mintz   ip6mr: Align hash...
897
898
899
900
  	struct mfc6_cache_cmp_arg arg = {
  		.mf6c_origin = in6addr_any,
  		.mf6c_mcastgrp = *mcastgrp,
  	};
660b26dc1   Nicolas Dichtel   mcast: add multic...
901
902
  
  	if (ipv6_addr_any(mcastgrp))
845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
903
904
  		return mr_mfc_find_any_parent(mrt, mifi);
  	return mr_mfc_find_any(mrt, mifi, &arg);
660b26dc1   Nicolas Dichtel   mcast: add multic...
905
  }
87c418bf1   Yuval Mintz   ip6mr: Align hash...
906
907
  /* Look for a (S,G,iif) entry if parent != -1 */
  static struct mfc6_cache *
b70432f73   Yuval Mintz   mroute*: Make mr_...
908
  ip6mr_cache_find_parent(struct mr_table *mrt,
87c418bf1   Yuval Mintz   ip6mr: Align hash...
909
910
911
912
913
914
915
916
  			const struct in6_addr *origin,
  			const struct in6_addr *mcastgrp,
  			int parent)
  {
  	struct mfc6_cache_cmp_arg arg = {
  		.mf6c_origin = *origin,
  		.mf6c_mcastgrp = *mcastgrp,
  	};
87c418bf1   Yuval Mintz   ip6mr: Align hash...
917

845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
918
  	return mr_mfc_find_parent(mrt, &arg, parent);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
919
  }
845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
920
  /* Allocate a multicast cache entry */
b5aa30b19   Patrick McHardy   ipv6: ip6mr: remo...
921
  static struct mfc6_cache *ip6mr_cache_alloc(void)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
922
  {
36cbac590   Joe Perches   net/ipv6/ip6mr.c:...
923
  	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
63159f29b   Ian Morris   ipv6: coding styl...
924
  	if (!c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
925
  		return NULL;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
926
927
  	c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1;
  	c->_c.mfc_un.res.minvif = MAXMIFS;
8c13af2a2   Yuval Mintz   ip6mr: Add refcou...
928
929
  	c->_c.free = ip6mr_cache_free_rcu;
  	refcount_set(&c->_c.mfc_un.res.refcount, 1);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
930
931
  	return c;
  }
b5aa30b19   Patrick McHardy   ipv6: ip6mr: remo...
932
  static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
933
  {
36cbac590   Joe Perches   net/ipv6/ip6mr.c:...
934
  	struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
63159f29b   Ian Morris   ipv6: coding styl...
935
  	if (!c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
936
  		return NULL;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
937
938
  	skb_queue_head_init(&c->_c.mfc_un.unres.unresolved);
  	c->_c.mfc_un.unres.expires = jiffies + 10 * HZ;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
939
940
941
942
943
944
  	return c;
  }
  
  /*
   *	A cache entry has gone into a resolved state from queued
   */
b70432f73   Yuval Mintz   mroute*: Make mr_...
945
  static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
946
  				struct mfc6_cache *uc, struct mfc6_cache *c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
947
948
949
950
951
952
  {
  	struct sk_buff *skb;
  
  	/*
  	 *	Play the pending entries through our router
  	 */
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
953
  	while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
954
  		if (ipv6_hdr(skb)->version == 0) {
af72868b9   Johannes Berg   networking: make ...
955
956
  			struct nlmsghdr *nlh = skb_pull(skb,
  							sizeof(struct ipv6hdr));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
957

7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
958
959
  			if (mr_fill_mroute(mrt, skb, &c->_c,
  					   nlmsg_data(nlh)) > 0) {
549e028d0   YOSHIFUJI Hideaki   [IPV6] MROUTE: Us...
960
  				nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
961
962
  			} else {
  				nlh->nlmsg_type = NLMSG_ERROR;
573ce260b   Hong zhi guo   net-next: replace...
963
  				nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
964
  				skb_trim(skb, nlh->nlmsg_len);
573ce260b   Hong zhi guo   net-next: replace...
965
  				((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
966
  			}
15e473046   Eric W. Biederman   netlink: Rename p...
967
  			rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
968
  		} else
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
969
  			ip6_mr_forward(net, mrt, skb->dev, skb, c);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
970
971
972
973
  	}
  }
  
  /*
dd12d15c9   Julien Gomes   ip6mr: add netlin...
974
   *	Bounce a cache query up to pim6sd and netlink.
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
975
976
977
   *
   *	Called under mrt_lock.
   */
b70432f73   Yuval Mintz   mroute*: Make mr_...
978
  static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
979
  			      mifi_t mifi, int assert)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
980
  {
8571ab479   Yuval Mintz   ip6mr: Make mrout...
981
  	struct sock *mroute6_sk;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
982
983
984
  	struct sk_buff *skb;
  	struct mrt6msg *msg;
  	int ret;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
985
986
987
988
989
990
991
  #ifdef CONFIG_IPV6_PIMSM_V2
  	if (assert == MRT6MSG_WHOLEPKT)
  		skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
  						+sizeof(*msg));
  	else
  #endif
  		skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
992
993
994
995
996
997
998
999
  
  	if (!skb)
  		return -ENOBUFS;
  
  	/* I suppose that internal messages
  	 * do not require checksums */
  
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  #ifdef CONFIG_IPV6_PIMSM_V2
  	if (assert == MRT6MSG_WHOLEPKT) {
  		/* Ugly, but we have no choice with this interface.
  		   Duplicate old header, fix length etc.
  		   And all this only to mangle msg->im6_msgtype and
  		   to set msg->im6_mbz to "mbz" :-)
  		 */
  		skb_push(skb, -skb_network_offset(pkt));
  
  		skb_push(skb, sizeof(*msg));
  		skb_reset_transport_header(skb);
  		msg = (struct mrt6msg *)skb_transport_header(skb);
  		msg->im6_mbz = 0;
  		msg->im6_msgtype = MRT6MSG_WHOLEPKT;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1014
  		msg->im6_mif = mrt->mroute_reg_vif_num;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1015
  		msg->im6_pad = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1016
1017
  		msg->im6_src = ipv6_hdr(pkt)->saddr;
  		msg->im6_dst = ipv6_hdr(pkt)->daddr;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1018
1019
1020
1021
1022
  
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
  	} else
  #endif
  	{
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  	/*
  	 *	Copy the IP header
  	 */
  
  	skb_put(skb, sizeof(struct ipv6hdr));
  	skb_reset_network_header(skb);
  	skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr));
  
  	/*
  	 *	Add our header
  	 */
  	skb_put(skb, sizeof(*msg));
  	skb_reset_transport_header(skb);
  	msg = (struct mrt6msg *)skb_transport_header(skb);
  
  	msg->im6_mbz = 0;
  	msg->im6_msgtype = assert;
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
1040
  	msg->im6_mif = mifi;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1041
  	msg->im6_pad = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
1042
1043
  	msg->im6_src = ipv6_hdr(pkt)->saddr;
  	msg->im6_dst = ipv6_hdr(pkt)->daddr;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1044

adf30907d   Eric Dumazet   net: skb->dst acc...
1045
  	skb_dst_set(skb, dst_clone(skb_dst(pkt)));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1046
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1047
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1048

8571ab479   Yuval Mintz   ip6mr: Make mrout...
1049
  	rcu_read_lock();
b70432f73   Yuval Mintz   mroute*: Make mr_...
1050
  	mroute6_sk = rcu_dereference(mrt->mroute_sk);
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1051
1052
  	if (!mroute6_sk) {
  		rcu_read_unlock();
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1053
1054
1055
  		kfree_skb(skb);
  		return -EINVAL;
  	}
dd12d15c9   Julien Gomes   ip6mr: add netlin...
1056
  	mrt6msg_netlink_event(mrt, skb);
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1057
1058
1059
  	/* Deliver to user space multicast routing algorithms */
  	ret = sock_queue_rcv_skb(mroute6_sk, skb);
  	rcu_read_unlock();
bd91b8bf3   Benjamin Thery   netns: ip6mr: all...
1060
  	if (ret < 0) {
e87cc4728   Joe Perches   net: Convert net_...
1061
1062
  		net_warn_ratelimited("mroute6: pending queue full, dropping entries
  ");
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1063
1064
1065
1066
1067
  		kfree_skb(skb);
  	}
  
  	return ret;
  }
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1068
1069
  /* Queue a packet for resolution. It gets locked cache entry! */
  static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1070
  				  struct sk_buff *skb, struct net_device *dev)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1071
  {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1072
  	struct mfc6_cache *c;
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1073
  	bool found = false;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1074
  	int err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1075
1076
  
  	spin_lock_bh(&mfc_unres_lock);
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1077
  	list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) {
c476efbcd   Patrick McHardy   ipv6: ip6mr: move...
1078
  		if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1079
1080
  		    ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
  			found = true;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1081
  			break;
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1082
  		}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1083
  	}
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1084
  	if (!found) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1085
1086
1087
  		/*
  		 *	Create a new entry if allowable
  		 */
0079ad8e8   Hangbin Liu   ipmr: remove hard...
1088
1089
  		c = ip6mr_cache_alloc_unres();
  		if (!c) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1090
1091
1092
1093
1094
  			spin_unlock_bh(&mfc_unres_lock);
  
  			kfree_skb(skb);
  			return -ENOBUFS;
  		}
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1095
1096
  		/* Fill in the new cache entry */
  		c->_c.mfc_parent = -1;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1097
1098
1099
1100
1101
1102
  		c->mf6c_origin = ipv6_hdr(skb)->saddr;
  		c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr;
  
  		/*
  		 *	Reflect first query at pim6sd
  		 */
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1103
  		err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1104
  		if (err < 0) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1105
1106
1107
1108
  			/* If the report failed throw the cache entry
  			   out - Brad Parker
  			 */
  			spin_unlock_bh(&mfc_unres_lock);
58701ad41   Benjamin Thery   netns: ip6mr: sto...
1109
  			ip6mr_cache_free(c);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1110
1111
1112
  			kfree_skb(skb);
  			return err;
  		}
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1113
  		atomic_inc(&mrt->cache_resolve_queue_len);
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1114
  		list_add(&c->_c.list, &mrt->mfc_unres_queue);
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
1115
  		mr6_netlink_event(mrt, c, RTM_NEWROUTE);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1116

6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1117
  		ipmr_do_expire_process(mrt);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1118
  	}
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1119
1120
  	/* See if we can append the packet */
  	if (c->_c.mfc_un.unres.unresolved.qlen > 3) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1121
1122
1123
  		kfree_skb(skb);
  		err = -ENOBUFS;
  	} else {
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1124
1125
1126
1127
  		if (dev) {
  			skb->dev = dev;
  			skb->skb_iif = dev->ifindex;
  		}
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1128
  		skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  		err = 0;
  	}
  
  	spin_unlock_bh(&mfc_unres_lock);
  	return err;
  }
  
  /*
   *	MFC6 cache manipulation by user space
   */
b70432f73   Yuval Mintz   mroute*: Make mr_...
1139
  static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc,
660b26dc1   Nicolas Dichtel   mcast: add multic...
1140
  			    int parent)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1141
  {
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1142
  	struct mfc6_cache *c;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1143

87c418bf1   Yuval Mintz   ip6mr: Align hash...
1144
1145
1146
1147
1148
1149
1150
  	/* The entries are added/deleted only under RTNL */
  	rcu_read_lock();
  	c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
  				    &mfc->mf6cc_mcastgrp.sin6_addr, parent);
  	rcu_read_unlock();
  	if (!c)
  		return -ENOENT;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1151
1152
  	rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params);
  	list_del_rcu(&c->_c.list);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1153

088aa3eec   Yuval Mintz   ip6mr: Support fi...
1154
1155
  	call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
  				       FIB_EVENT_ENTRY_DEL, c, mrt->id);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1156
  	mr6_netlink_event(mrt, c, RTM_DELROUTE);
8c13af2a2   Yuval Mintz   ip6mr: Add refcou...
1157
  	mr_cache_put(&c->_c);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1158
  	return 0;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1159
1160
1161
1162
1163
  }
  
  static int ip6mr_device_event(struct notifier_block *this,
  			      unsigned long event, void *ptr)
  {
351638e7d   Jiri Pirko   net: pass info st...
1164
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1165
  	struct net *net = dev_net(dev);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1166
  	struct mr_table *mrt;
6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
1167
  	struct vif_device *v;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1168
  	int ct;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1169
1170
  	if (event != NETDEV_UNREGISTER)
  		return NOTIFY_DONE;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1171
  	ip6mr_for_each_table(mrt, net) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1172
  		v = &mrt->vif_table[0];
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1173
1174
  		for (ct = 0; ct < mrt->maxvif; ct++, v++) {
  			if (v->dev == dev)
723b929ca   Nikolay Aleksandrov   ip6mr: fix notifi...
1175
  				mif6_delete(mrt, ct, 1, NULL);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1176
  		}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1177
  	}
c871e664e   Eric Dumazet   ip6mr: Optimize m...
1178

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1179
1180
  	return NOTIFY_DONE;
  }
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1181
1182
1183
1184
1185
1186
  static unsigned int ip6mr_seq_read(struct net *net)
  {
  	ASSERT_RTNL();
  
  	return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net);
  }
b7a595577   Jiri Pirko   net: fib_notifier...
1187
1188
  static int ip6mr_dump(struct net *net, struct notifier_block *nb,
  		      struct netlink_ext_ack *extack)
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1189
1190
  {
  	return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
b7a595577   Jiri Pirko   net: fib_notifier...
1191
  		       ip6mr_mr_table_iter, &mrt_lock, extack);
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1192
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1193
1194
1195
  static struct notifier_block ip6_mr_notifier = {
  	.notifier_call = ip6mr_device_event
  };
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
  static const struct fib_notifier_ops ip6mr_notifier_ops_template = {
  	.family		= RTNL_FAMILY_IP6MR,
  	.fib_seq_read	= ip6mr_seq_read,
  	.fib_dump	= ip6mr_dump,
  	.owner		= THIS_MODULE,
  };
  
  static int __net_init ip6mr_notifier_init(struct net *net)
  {
  	struct fib_notifier_ops *ops;
  
  	net->ipv6.ipmr_seq = 0;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1208

088aa3eec   Yuval Mintz   ip6mr: Support fi...
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  	ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  
  	net->ipv6.ip6mr_notifier_ops = ops;
  
  	return 0;
  }
  
  static void __net_exit ip6mr_notifier_exit(struct net *net)
  {
  	fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops);
  	net->ipv6.ip6mr_notifier_ops = NULL;
  }
  
  /* Setup for IP multicast routing */
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1225
1226
  static int __net_init ip6mr_net_init(struct net *net)
  {
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1227
  	int err;
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1228

088aa3eec   Yuval Mintz   ip6mr: Support fi...
1229
1230
1231
  	err = ip6mr_notifier_init(net);
  	if (err)
  		return err;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1232
1233
  	err = ip6mr_rules_init(net);
  	if (err < 0)
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1234
  		goto ip6mr_rules_fail;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1235
1236
1237
  
  #ifdef CONFIG_PROC_FS
  	err = -ENOMEM;
c35063722   Christoph Hellwig   proc: introduce p...
1238
1239
  	if (!proc_create_net("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_seq_ops,
  			sizeof(struct mr_vif_iter)))
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1240
  		goto proc_vif_fail;
c35063722   Christoph Hellwig   proc: introduce p...
1241
1242
  	if (!proc_create_net("ip6_mr_cache", 0, net->proc_net, &ipmr_mfc_seq_ops,
  			sizeof(struct mr_mfc_iter)))
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1243
1244
  		goto proc_cache_fail;
  #endif
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1245

4a6258a0e   Benjamin Thery   netns: ip6mr: dyn...
1246
  	return 0;
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1247
1248
  #ifdef CONFIG_PROC_FS
  proc_cache_fail:
ece31ffd5   Gao feng   net: proc: change...
1249
  	remove_proc_entry("ip6_mr_vif", net->proc_net);
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1250
  proc_vif_fail:
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1251
  	ip6mr_rules_exit(net);
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1252
  #endif
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1253
1254
  ip6mr_rules_fail:
  	ip6mr_notifier_exit(net);
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1255
1256
1257
1258
1259
  	return err;
  }
  
  static void __net_exit ip6mr_net_exit(struct net *net)
  {
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1260
  #ifdef CONFIG_PROC_FS
ece31ffd5   Gao feng   net: proc: change...
1261
1262
  	remove_proc_entry("ip6_mr_cache", net->proc_net);
  	remove_proc_entry("ip6_mr_vif", net->proc_net);
8b90fc7e5   Benjamin Thery   netns: ip6mr: dec...
1263
  #endif
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1264
  	ip6mr_rules_exit(net);
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1265
  	ip6mr_notifier_exit(net);
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1266
1267
1268
1269
1270
1271
  }
  
  static struct pernet_operations ip6mr_net_ops = {
  	.init = ip6mr_net_init,
  	.exit = ip6mr_net_exit,
  };
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1272
  int __init ip6_mr_init(void)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1273
  {
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1274
  	int err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1275
1276
1277
1278
1279
  	mrt_cachep = kmem_cache_create("ip6_mrt_cache",
  				       sizeof(struct mfc6_cache),
  				       0, SLAB_HWCACHE_ALIGN,
  				       NULL);
  	if (!mrt_cachep)
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1280
  		return -ENOMEM;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1281

4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1282
1283
1284
  	err = register_pernet_subsys(&ip6mr_net_ops);
  	if (err)
  		goto reg_pernet_fail;
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1285
1286
1287
  	err = register_netdevice_notifier(&ip6_mr_notifier);
  	if (err)
  		goto reg_notif_fail;
403dbb97f   Tom Goff   PIM-SM: namespace...
1288
1289
  #ifdef CONFIG_IPV6_PIMSM_V2
  	if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
1290
1291
  		pr_err("%s: can't add PIM protocol
  ", __func__);
403dbb97f   Tom Goff   PIM-SM: namespace...
1292
1293
1294
1295
  		err = -EAGAIN;
  		goto add_proto_fail;
  	}
  #endif
a3fde2add   Florian Westphal   rtnetlink: ipv6: ...
1296
1297
1298
1299
  	err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE,
  				   NULL, ip6mr_rtm_dumproute, 0);
  	if (err == 0)
  		return 0;
403dbb97f   Tom Goff   PIM-SM: namespace...
1300
  #ifdef CONFIG_IPV6_PIMSM_V2
a3fde2add   Florian Westphal   rtnetlink: ipv6: ...
1301
  	inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
403dbb97f   Tom Goff   PIM-SM: namespace...
1302
1303
1304
  add_proto_fail:
  	unregister_netdevice_notifier(&ip6_mr_notifier);
  #endif
87b30a653   Benjamin Thery   ipv6: fix ip6_mr_...
1305
  reg_notif_fail:
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1306
1307
  	unregister_pernet_subsys(&ip6mr_net_ops);
  reg_pernet_fail:
87b30a653   Benjamin Thery   ipv6: fix ip6_mr_...
1308
  	kmem_cache_destroy(mrt_cachep);
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1309
  	return err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1310
  }
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1311
1312
  void ip6_mr_cleanup(void)
  {
ffb1388a3   Duan Jiong   ipv6: delete prot...
1313
1314
1315
1316
  	rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE);
  #ifdef CONFIG_IPV6_PIMSM_V2
  	inet6_del_protocol(&pim6_protocol, IPPROTO_PIM);
  #endif
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1317
  	unregister_netdevice_notifier(&ip6_mr_notifier);
4e16880cb   Benjamin Thery   netns: ip6mr: dyn...
1318
  	unregister_pernet_subsys(&ip6mr_net_ops);
623d1a1af   Wang Chen   ipv6: Do cleanup ...
1319
1320
  	kmem_cache_destroy(mrt_cachep);
  }
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1321

b70432f73   Yuval Mintz   mroute*: Make mr_...
1322
  static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
660b26dc1   Nicolas Dichtel   mcast: add multic...
1323
  			 struct mf6cctl *mfc, int mrtsock, int parent)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1324
  {
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
1325
  	unsigned char ttls[MAXMIFS];
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1326
  	struct mfc6_cache *uc, *c;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1327
  	struct mr_mfc *_uc;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1328
1329
  	bool found;
  	int i, err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1330

a50436f2c   Patrick McHardy   net: ipmr/ip6mr: ...
1331
1332
  	if (mfc->mf6cc_parent >= MAXMIFS)
  		return -ENFILE;
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
1333
1334
  	memset(ttls, 255, MAXMIFS);
  	for (i = 0; i < MAXMIFS; i++) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1335
1336
  		if (IF_ISSET(i, &mfc->mf6cc_ifset))
  			ttls[i] = 1;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1337
  	}
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1338
1339
1340
1341
1342
1343
  	/* The entries are added/deleted only under RTNL */
  	rcu_read_lock();
  	c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr,
  				    &mfc->mf6cc_mcastgrp.sin6_addr, parent);
  	rcu_read_unlock();
  	if (c) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1344
  		write_lock_bh(&mrt_lock);
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1345
1346
  		c->_c.mfc_parent = mfc->mf6cc_parent;
  		ip6mr_update_thresholds(mrt, &c->_c, ttls);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1347
  		if (!mrtsock)
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1348
  			c->_c.mfc_flags |= MFC_STATIC;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1349
  		write_unlock_bh(&mrt_lock);
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1350
1351
  		call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
  					       c, mrt->id);
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
1352
  		mr6_netlink_event(mrt, c, RTM_NEWROUTE);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1353
1354
  		return 0;
  	}
660b26dc1   Nicolas Dichtel   mcast: add multic...
1355
1356
  	if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
  	    !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1357
  		return -EINVAL;
b5aa30b19   Patrick McHardy   ipv6: ip6mr: remo...
1358
  	c = ip6mr_cache_alloc();
63159f29b   Ian Morris   ipv6: coding styl...
1359
  	if (!c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1360
1361
1362
1363
  		return -ENOMEM;
  
  	c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
  	c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1364
1365
  	c->_c.mfc_parent = mfc->mf6cc_parent;
  	ip6mr_update_thresholds(mrt, &c->_c, ttls);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1366
  	if (!mrtsock)
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1367
  		c->_c.mfc_flags |= MFC_STATIC;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1368

494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1369
  	err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode,
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1370
1371
1372
1373
1374
1375
1376
  				  ip6mr_rht_params);
  	if (err) {
  		pr_err("ip6mr: rhtable insert error %d
  ", err);
  		ip6mr_cache_free(c);
  		return err;
  	}
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1377
  	list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1378

87c418bf1   Yuval Mintz   ip6mr: Align hash...
1379
1380
  	/* Check to see if we resolved a queued list. If so we
  	 * need to send on the frames and tidy up.
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1381
  	 */
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1382
  	found = false;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1383
  	spin_lock_bh(&mfc_unres_lock);
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1384
1385
  	list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) {
  		uc = (struct mfc6_cache *)_uc;
c476efbcd   Patrick McHardy   ipv6: ip6mr: move...
1386
  		if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1387
  		    ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1388
  			list_del(&_uc->list);
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1389
  			atomic_dec(&mrt->cache_resolve_queue_len);
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1390
  			found = true;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1391
1392
1393
  			break;
  		}
  	}
b70432f73   Yuval Mintz   mroute*: Make mr_...
1394
  	if (list_empty(&mrt->mfc_unres_queue))
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1395
  		del_timer(&mrt->ipmr_expire_timer);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1396
  	spin_unlock_bh(&mfc_unres_lock);
f30a77842   Patrick McHardy   ipv6: ip6mr: conv...
1397
  	if (found) {
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1398
  		ip6mr_cache_resolve(net, mrt, uc, c);
58701ad41   Benjamin Thery   netns: ip6mr: sto...
1399
  		ip6mr_cache_free(uc);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1400
  	}
088aa3eec   Yuval Mintz   ip6mr: Support fi...
1401
1402
  	call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD,
  				       c, mrt->id);
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
1403
  	mr6_netlink_event(mrt, c, RTM_NEWROUTE);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1404
1405
1406
1407
1408
1409
  	return 0;
  }
  
  /*
   *	Close the multicast socket, and clear the vif tables etc
   */
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1410
  static void mroute_clean_tables(struct mr_table *mrt, int flags)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1411
  {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1412
  	struct mr_mfc *c, *tmp;
c871e664e   Eric Dumazet   ip6mr: Optimize m...
1413
  	LIST_HEAD(list);
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1414
  	int i;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1415

87c418bf1   Yuval Mintz   ip6mr: Align hash...
1416
  	/* Shut down all active vif entries */
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1417
1418
1419
1420
1421
1422
1423
1424
1425
  	if (flags & (MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC)) {
  		for (i = 0; i < mrt->maxvif; i++) {
  			if (((mrt->vif_table[i].flags & VIFF_STATIC) &&
  			     !(flags & MRT6_FLUSH_MIFS_STATIC)) ||
  			    (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT6_FLUSH_MIFS)))
  				continue;
  			mif6_delete(mrt, i, 0, &list);
  		}
  		unregister_netdevice_many(&list);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1426
  	}
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1427
  	/* Wipe the cache */
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  	if (flags & (MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC)) {
  		list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) {
  			if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC_STATIC)) ||
  			    (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC)))
  				continue;
  			rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params);
  			list_del_rcu(&c->list);
  			call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net),
  						       FIB_EVENT_ENTRY_DEL,
  						       (struct mfc6_cache *)c, mrt->id);
  			mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE);
  			mr_cache_put(c);
  		}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1441
  	}
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
  	if (flags & MRT6_FLUSH_MFC) {
  		if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
  			spin_lock_bh(&mfc_unres_lock);
  			list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
  				list_del(&c->list);
  				mr6_netlink_event(mrt, (struct mfc6_cache *)c,
  						  RTM_DELROUTE);
  				ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c);
  			}
  			spin_unlock_bh(&mfc_unres_lock);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1452
  		}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1453
1454
  	}
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
1455
  static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1456
1457
  {
  	int err = 0;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1458
  	struct net *net = sock_net(sk);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1459
1460
1461
  
  	rtnl_lock();
  	write_lock_bh(&mrt_lock);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1462
  	if (rtnl_dereference(mrt->mroute_sk)) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1463
  		err = -EADDRINUSE;
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1464
  	} else {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1465
  		rcu_assign_pointer(mrt->mroute_sk, sk);
a366e300a   Eric Dumazet   ip6mr: remove syn...
1466
  		sock_set_flag(sk, SOCK_RCU_FREE);
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1467
  		net->ipv6.devconf_all->mc_forwarding++;
927265bc6   Eric Dumazet   ipv6: do not abus...
1468
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1469
  	write_unlock_bh(&mrt_lock);
927265bc6   Eric Dumazet   ipv6: do not abus...
1470
  	if (!err)
85b3daada   David Ahern   net: ipv6: Refact...
1471
1472
  		inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
  					     NETCONFA_MC_FORWARDING,
927265bc6   Eric Dumazet   ipv6: do not abus...
1473
1474
  					     NETCONFA_IFINDEX_ALL,
  					     net->ipv6.devconf_all);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1475
1476
1477
1478
1479
1480
1481
  	rtnl_unlock();
  
  	return err;
  }
  
  int ip6mr_sk_done(struct sock *sk)
  {
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1482
  	int err = -EACCES;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1483
  	struct net *net = sock_net(sk);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1484
  	struct mr_table *mrt;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1485

338d182fa   Francesco Ruggeri   ipv6: try not to ...
1486
1487
1488
  	if (sk->sk_type != SOCK_RAW ||
  	    inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  		return err;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1489
  	rtnl_lock();
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1490
  	ip6mr_for_each_table(mrt, net) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1491
  		if (sk == rtnl_dereference(mrt->mroute_sk)) {
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1492
  			write_lock_bh(&mrt_lock);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1493
  			RCU_INIT_POINTER(mrt->mroute_sk, NULL);
a366e300a   Eric Dumazet   ip6mr: remove syn...
1494
1495
1496
1497
  			/* Note that mroute_sk had SOCK_RCU_FREE set,
  			 * so the RCU grace period before sk freeing
  			 * is guaranteed by sk_destruct()
  			 */
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1498
  			net->ipv6.devconf_all->mc_forwarding--;
927265bc6   Eric Dumazet   ipv6: do not abus...
1499
  			write_unlock_bh(&mrt_lock);
85b3daada   David Ahern   net: ipv6: Refact...
1500
  			inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
d67b8c616   Nicolas Dichtel   netconf: advertis...
1501
1502
1503
  						     NETCONFA_MC_FORWARDING,
  						     NETCONFA_IFINDEX_ALL,
  						     net->ipv6.devconf_all);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1504

ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1505
  			mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1506
1507
1508
1509
  			err = 0;
  			break;
  		}
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1510
1511
1512
1513
  	rtnl_unlock();
  
  	return err;
  }
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1514
  bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1515
  {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1516
  	struct mr_table *mrt;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1517
  	struct flowi6 fl6 = {
e374c618b   Julian Anastasov   net: ipv6: more p...
1518
  		.flowi6_iif	= skb->skb_iif ? : LOOPBACK_IFINDEX,
4c9483b2f   David S. Miller   ipv6: Convert to ...
1519
1520
  		.flowi6_oif	= skb->dev->ifindex,
  		.flowi6_mark	= skb->mark,
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1521
  	};
4c9483b2f   David S. Miller   ipv6: Convert to ...
1522
  	if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1523
  		return NULL;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1524

b70432f73   Yuval Mintz   mroute*: Make mr_...
1525
  	return rcu_access_pointer(mrt->mroute_sk);
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1526
  }
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1527
  EXPORT_SYMBOL(mroute6_is_socket);
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1528

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1529
1530
1531
1532
1533
1534
  /*
   *	Socket options and virtual interface manipulation. The whole
   *	virtual interface system is a complete heap, but unfortunately
   *	that's how BSD mrouted happens to think. Maybe one day with a proper
   *	MOSPF/PIM router set up we can clean this up.
   */
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1535
1536
  int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
  			  unsigned int optlen)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1537
  {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1538
  	int ret, parent = 0;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1539
1540
1541
  	struct mif6ctl vif;
  	struct mf6cctl mfc;
  	mifi_t mifi;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1542
  	struct net *net = sock_net(sk);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1543
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1544

99253eb75   Xin Long   ipv6: check sk sk...
1545
1546
1547
  	if (sk->sk_type != SOCK_RAW ||
  	    inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  		return -EOPNOTSUPP;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1548
  	mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
1549
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1550
  		return -ENOENT;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1551
1552
  
  	if (optname != MRT6_INIT) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1553
  		if (sk != rcu_access_pointer(mrt->mroute_sk) &&
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1554
  		    !ns_capable(net->user_ns, CAP_NET_ADMIN))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1555
1556
1557
1558
1559
  			return -EACCES;
  	}
  
  	switch (optname) {
  	case MRT6_INIT:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1560
1561
  		if (optlen < sizeof(int))
  			return -EINVAL;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1562
  		return ip6mr_sk_init(mrt, sk);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1563
1564
1565
1566
1567
1568
1569
  
  	case MRT6_DONE:
  		return ip6mr_sk_done(sk);
  
  	case MRT6_ADD_MIF:
  		if (optlen < sizeof(vif))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1570
  		if (copy_from_sockptr(&vif, optval, sizeof(vif)))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1571
  			return -EFAULT;
6ac7eb086   Rami Rosen   [IPV6] MROUTE: Ad...
1572
  		if (vif.mif6c_mifi >= MAXMIFS)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1573
1574
  			return -ENFILE;
  		rtnl_lock();
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1575
  		ret = mif6_add(net, mrt, &vif,
b70432f73   Yuval Mintz   mroute*: Make mr_...
1576
  			       sk == rtnl_dereference(mrt->mroute_sk));
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1577
1578
1579
1580
1581
1582
  		rtnl_unlock();
  		return ret;
  
  	case MRT6_DEL_MIF:
  		if (optlen < sizeof(mifi_t))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1583
  		if (copy_from_sockptr(&mifi, optval, sizeof(mifi_t)))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1584
1585
  			return -EFAULT;
  		rtnl_lock();
723b929ca   Nikolay Aleksandrov   ip6mr: fix notifi...
1586
  		ret = mif6_delete(mrt, mifi, 0, NULL);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1587
1588
1589
1590
1591
1592
1593
1594
1595
  		rtnl_unlock();
  		return ret;
  
  	/*
  	 *	Manipulate the forwarding caches. These live
  	 *	in a sort of kernel/user symbiosis.
  	 */
  	case MRT6_ADD_MFC:
  	case MRT6_DEL_MFC:
660b26dc1   Nicolas Dichtel   mcast: add multic...
1596
  		parent = -1;
a8eceea84   Joe Perches   inet: Use fallthr...
1597
  		fallthrough;
660b26dc1   Nicolas Dichtel   mcast: add multic...
1598
1599
  	case MRT6_ADD_MFC_PROXY:
  	case MRT6_DEL_MFC_PROXY:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1600
1601
  		if (optlen < sizeof(mfc))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1602
  		if (copy_from_sockptr(&mfc, optval, sizeof(mfc)))
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1603
  			return -EFAULT;
660b26dc1   Nicolas Dichtel   mcast: add multic...
1604
1605
  		if (parent == 0)
  			parent = mfc.mf6cc_parent;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1606
  		rtnl_lock();
660b26dc1   Nicolas Dichtel   mcast: add multic...
1607
1608
  		if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
  			ret = ip6mr_mfc_delete(mrt, &mfc, parent);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1609
  		else
660b26dc1   Nicolas Dichtel   mcast: add multic...
1610
  			ret = ip6mr_mfc_add(net, mrt, &mfc,
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1611
  					    sk ==
b70432f73   Yuval Mintz   mroute*: Make mr_...
1612
  					    rtnl_dereference(mrt->mroute_sk),
8571ab479   Yuval Mintz   ip6mr: Make mrout...
1613
  					    parent);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1614
1615
  		rtnl_unlock();
  		return ret;
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1616
1617
1618
1619
1620
1621
  	case MRT6_FLUSH:
  	{
  		int flags;
  
  		if (optlen != sizeof(flags))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1622
  		if (copy_from_sockptr(&flags, optval, sizeof(flags)))
ca8d4794f   Callum Sinclair   ipmr: ip6mr: Crea...
1623
1624
1625
1626
1627
1628
  			return -EFAULT;
  		rtnl_lock();
  		mroute_clean_tables(mrt, flags);
  		rtnl_unlock();
  		return 0;
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1629
  	/*
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1630
1631
1632
1633
1634
  	 *	Control PIM assert (to activate pim will activate assert)
  	 */
  	case MRT6_ASSERT:
  	{
  		int v;
03f52a0a5   Joe Perches   ip6mr: Add sizeof...
1635
1636
1637
  
  		if (optlen != sizeof(v))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1638
  		if (copy_from_sockptr(&v, optval, sizeof(v)))
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1639
  			return -EFAULT;
53d6841d2   Joe Perches   ipv4/ipmr and ipv...
1640
  		mrt->mroute_do_assert = v;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1641
1642
1643
1644
1645
1646
  		return 0;
  	}
  
  #ifdef CONFIG_IPV6_PIMSM_V2
  	case MRT6_PIM:
  	{
a9f83bf38   YOSHIFUJI Hideaki   [IPV6]: Sparse: R...
1647
  		int v;
03f52a0a5   Joe Perches   ip6mr: Add sizeof...
1648
1649
1650
  
  		if (optlen != sizeof(v))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1651
  		if (copy_from_sockptr(&v, optval, sizeof(v)))
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1652
1653
1654
1655
  			return -EFAULT;
  		v = !!v;
  		rtnl_lock();
  		ret = 0;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1656
1657
1658
  		if (v != mrt->mroute_do_pim) {
  			mrt->mroute_do_pim = v;
  			mrt->mroute_do_assert = v;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1659
1660
1661
1662
1663
1664
  		}
  		rtnl_unlock();
  		return ret;
  	}
  
  #endif
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1665
1666
1667
1668
1669
1670
1671
  #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
  	case MRT6_TABLE:
  	{
  		u32 v;
  
  		if (optlen != sizeof(u32))
  			return -EINVAL;
b43c61531   Christoph Hellwig   net/ipv6: switch ...
1672
  		if (copy_from_sockptr(&v, optval, sizeof(v)))
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1673
  			return -EFAULT;
75356a814   Dan Carpenter   ip6mr: limit IPv6...
1674
1675
1676
  		/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
  		if (v != RT_TABLE_DEFAULT && v >= 100000000)
  			return -EINVAL;
b70432f73   Yuval Mintz   mroute*: Make mr_...
1677
  		if (sk == rcu_access_pointer(mrt->mroute_sk))
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1678
1679
1680
1681
  			return -EBUSY;
  
  		rtnl_lock();
  		ret = 0;
e783bb00a   Sabrina Dubroca   ipmr: fix error p...
1682
1683
1684
  		mrt = ip6mr_new_table(net, v);
  		if (IS_ERR(mrt))
  			ret = PTR_ERR(mrt);
848235edb   Sabrina Dubroca   ip6mr: only set i...
1685
1686
  		else
  			raw6_sk(sk)->ip6mr_table = v;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1687
1688
1689
1690
  		rtnl_unlock();
  		return ret;
  	}
  #endif
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1691
  	/*
7d120c55d   Rami Rosen   ipv6 mroute: Use ...
1692
  	 *	Spurious command, or MRT6_VERSION which you cannot
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
  	 *	set.
  	 */
  	default:
  		return -ENOPROTOOPT;
  	}
  }
  
  /*
   *	Getsock opt support for the multicast routing system.
   */
  
  int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
  			  int __user *optlen)
  {
  	int olr;
  	int val;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1709
  	struct net *net = sock_net(sk);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1710
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1711

99253eb75   Xin Long   ipv6: check sk sk...
1712
1713
1714
  	if (sk->sk_type != SOCK_RAW ||
  	    inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
  		return -EOPNOTSUPP;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1715
  	mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
1716
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1717
  		return -ENOENT;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1718
1719
1720
1721
1722
  
  	switch (optname) {
  	case MRT6_VERSION:
  		val = 0x0305;
  		break;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1723
1724
  #ifdef CONFIG_IPV6_PIMSM_V2
  	case MRT6_PIM:
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1725
  		val = mrt->mroute_do_pim;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1726
1727
1728
  		break;
  #endif
  	case MRT6_ASSERT:
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1729
  		val = mrt->mroute_do_assert;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1730
  		break;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
  	default:
  		return -ENOPROTOOPT;
  	}
  
  	if (get_user(olr, optlen))
  		return -EFAULT;
  
  	olr = min_t(int, olr, sizeof(int));
  	if (olr < 0)
  		return -EINVAL;
  
  	if (put_user(olr, optlen))
  		return -EFAULT;
  	if (copy_to_user(optval, &val, olr))
  		return -EFAULT;
  	return 0;
  }
  
  /*
   *	The IP multicast ioctl support routines.
   */
  
  int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
  {
  	struct sioc_sg_req6 sr;
  	struct sioc_mif_req6 vr;
6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
1757
  	struct vif_device *vif;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1758
  	struct mfc6_cache *c;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
1759
  	struct net *net = sock_net(sk);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1760
  	struct mr_table *mrt;
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1761
1762
  
  	mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
1763
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
1764
  		return -ENOENT;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1765
1766
1767
1768
1769
  
  	switch (cmd) {
  	case SIOCGETMIFCNT_IN6:
  		if (copy_from_user(&vr, arg, sizeof(vr)))
  			return -EFAULT;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1770
  		if (vr.mifi >= mrt->maxvif)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1771
  			return -EINVAL;
69d2c8676   Gustavo A. R. Silva   ip6mr: Fix potent...
1772
  		vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1773
  		read_lock(&mrt_lock);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1774
1775
  		vif = &mrt->vif_table[vr.mifi];
  		if (VIF_EXISTS(mrt, vr.mifi)) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
  			vr.icount = vif->pkt_in;
  			vr.ocount = vif->pkt_out;
  			vr.ibytes = vif->bytes_in;
  			vr.obytes = vif->bytes_out;
  			read_unlock(&mrt_lock);
  
  			if (copy_to_user(arg, &vr, sizeof(vr)))
  				return -EFAULT;
  			return 0;
  		}
  		read_unlock(&mrt_lock);
  		return -EADDRNOTAVAIL;
  	case SIOCGETSGCNT_IN6:
  		if (copy_from_user(&sr, arg, sizeof(sr)))
  			return -EFAULT;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1791
  		rcu_read_lock();
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1792
  		c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1793
  		if (c) {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1794
1795
1796
  			sr.pktcnt = c->_c.mfc_un.res.pkt;
  			sr.bytecnt = c->_c.mfc_un.res.bytes;
  			sr.wrong_if = c->_c.mfc_un.res.wrong_if;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1797
  			rcu_read_unlock();
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1798
1799
1800
1801
1802
  
  			if (copy_to_user(arg, &sr, sizeof(sr)))
  				return -EFAULT;
  			return 0;
  		}
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1803
  		rcu_read_unlock();
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1804
1805
1806
1807
1808
  		return -EADDRNOTAVAIL;
  	default:
  		return -ENOIOCTLCMD;
  	}
  }
e2d57766e   David S. Miller   net: Provide comp...
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
  #ifdef CONFIG_COMPAT
  struct compat_sioc_sg_req6 {
  	struct sockaddr_in6 src;
  	struct sockaddr_in6 grp;
  	compat_ulong_t pktcnt;
  	compat_ulong_t bytecnt;
  	compat_ulong_t wrong_if;
  };
  
  struct compat_sioc_mif_req6 {
  	mifi_t	mifi;
  	compat_ulong_t icount;
  	compat_ulong_t ocount;
  	compat_ulong_t ibytes;
  	compat_ulong_t obytes;
  };
  
  int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
  {
  	struct compat_sioc_sg_req6 sr;
  	struct compat_sioc_mif_req6 vr;
6853f21f7   Yuval Mintz   ipmr,ipmr6: Defin...
1830
  	struct vif_device *vif;
e2d57766e   David S. Miller   net: Provide comp...
1831
1832
  	struct mfc6_cache *c;
  	struct net *net = sock_net(sk);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1833
  	struct mr_table *mrt;
e2d57766e   David S. Miller   net: Provide comp...
1834
1835
  
  	mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
1836
  	if (!mrt)
e2d57766e   David S. Miller   net: Provide comp...
1837
1838
1839
1840
1841
1842
1843
1844
  		return -ENOENT;
  
  	switch (cmd) {
  	case SIOCGETMIFCNT_IN6:
  		if (copy_from_user(&vr, arg, sizeof(vr)))
  			return -EFAULT;
  		if (vr.mifi >= mrt->maxvif)
  			return -EINVAL;
69d2c8676   Gustavo A. R. Silva   ip6mr: Fix potent...
1845
  		vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
e2d57766e   David S. Miller   net: Provide comp...
1846
  		read_lock(&mrt_lock);
b70432f73   Yuval Mintz   mroute*: Make mr_...
1847
1848
  		vif = &mrt->vif_table[vr.mifi];
  		if (VIF_EXISTS(mrt, vr.mifi)) {
e2d57766e   David S. Miller   net: Provide comp...
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
  			vr.icount = vif->pkt_in;
  			vr.ocount = vif->pkt_out;
  			vr.ibytes = vif->bytes_in;
  			vr.obytes = vif->bytes_out;
  			read_unlock(&mrt_lock);
  
  			if (copy_to_user(arg, &vr, sizeof(vr)))
  				return -EFAULT;
  			return 0;
  		}
  		read_unlock(&mrt_lock);
  		return -EADDRNOTAVAIL;
  	case SIOCGETSGCNT_IN6:
  		if (copy_from_user(&sr, arg, sizeof(sr)))
  			return -EFAULT;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1864
  		rcu_read_lock();
e2d57766e   David S. Miller   net: Provide comp...
1865
1866
  		c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
  		if (c) {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1867
1868
1869
  			sr.pktcnt = c->_c.mfc_un.res.pkt;
  			sr.bytecnt = c->_c.mfc_un.res.bytes;
  			sr.wrong_if = c->_c.mfc_un.res.wrong_if;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1870
  			rcu_read_unlock();
e2d57766e   David S. Miller   net: Provide comp...
1871
1872
1873
1874
1875
  
  			if (copy_to_user(arg, &sr, sizeof(sr)))
  				return -EFAULT;
  			return 0;
  		}
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1876
  		rcu_read_unlock();
e2d57766e   David S. Miller   net: Provide comp...
1877
1878
1879
1880
1881
1882
  		return -EADDRNOTAVAIL;
  	default:
  		return -ENOIOCTLCMD;
  	}
  }
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1883

0c4b51f00   Eric W. Biederman   netfilter: Pass n...
1884
  static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1885
  {
87c11f1dd   Ido Schimmel   ip6mr: Do not cal...
1886
1887
1888
1889
  	IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
  		      IPSTATS_MIB_OUTFORWDATAGRAMS);
  	IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
  		      IPSTATS_MIB_OUTOCTETS, skb->len);
13206b6bf   Eric W. Biederman   net: Pass net int...
1890
  	return dst_output(net, sk, skb);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1891
1892
1893
1894
1895
  }
  
  /*
   *	Processing handlers for ip6mr_forward
   */
b70432f73   Yuval Mintz   mroute*: Make mr_...
1896
  static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
f5c6dfdef   David Ahern   ip6mr: Drop mfc6_...
1897
  			  struct sk_buff *skb, int vifi)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1898
1899
  {
  	struct ipv6hdr *ipv6h;
b70432f73   Yuval Mintz   mroute*: Make mr_...
1900
  	struct vif_device *vif = &mrt->vif_table[vifi];
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1901
1902
  	struct net_device *dev;
  	struct dst_entry *dst;
4c9483b2f   David S. Miller   ipv6: Convert to ...
1903
  	struct flowi6 fl6;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1904

63159f29b   Ian Morris   ipv6: coding styl...
1905
  	if (!vif->dev)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1906
  		goto out_free;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1907
1908
1909
1910
  #ifdef CONFIG_IPV6_PIMSM_V2
  	if (vif->flags & MIFF_REGISTER) {
  		vif->pkt_out++;
  		vif->bytes_out += skb->len;
dc58c78c0   Pavel Emelyanov   ip6mr: Use on-dev...
1911
1912
  		vif->dev->stats.tx_bytes += skb->len;
  		vif->dev->stats.tx_packets++;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1913
  		ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
8da73b73e   Ilpo Järvinen   ip6mr: use goto t...
1914
  		goto out_free;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1915
1916
  	}
  #endif
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1917
  	ipv6h = ipv6_hdr(skb);
4c9483b2f   David S. Miller   ipv6: Convert to ...
1918
1919
1920
  	fl6 = (struct flowi6) {
  		.flowi6_oif = vif->link,
  		.daddr = ipv6h->daddr,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1921
  	};
4c9483b2f   David S. Miller   ipv6: Convert to ...
1922
  	dst = ip6_route_output(net, NULL, &fl6);
5095d64db   RongQing.Li   ipv6: ip6_route_o...
1923
1924
  	if (dst->error) {
  		dst_release(dst);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1925
  		goto out_free;
5095d64db   RongQing.Li   ipv6: ip6_route_o...
1926
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1927

adf30907d   Eric Dumazet   net: skb->dst acc...
1928
1929
  	skb_dst_drop(skb);
  	skb_dst_set(skb, dst);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
  
  	/*
  	 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
  	 * not only before forwarding, but after forwarding on all output
  	 * interfaces. It is clear, if mrouter runs a multicasting
  	 * program, it should receive packets not depending to what interface
  	 * program is joined.
  	 * If we will not make it, the program will have to join on all
  	 * interfaces. On the other hand, multihoming host (or router, but
  	 * not mrouter) cannot join to more than one interface - it will
  	 * result in receiving multiple packets.
  	 */
  	dev = vif->dev;
  	skb->dev = dev;
  	vif->pkt_out++;
  	vif->bytes_out += skb->len;
  
  	/* We are about to write */
  	/* XXX: extension headers? */
  	if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
  		goto out_free;
  
  	ipv6h = ipv6_hdr(skb);
  	ipv6h->hop_limit--;
  
  	IP6CB(skb)->flags |= IP6SKB_FORWARDED;
29a26a568   Eric W. Biederman   netfilter: Pass s...
1956
1957
  	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
  		       net, NULL, skb, skb->dev, dev,
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1958
1959
1960
1961
1962
1963
  		       ip6mr_forward2_finish);
  
  out_free:
  	kfree_skb(skb);
  	return 0;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
1964
  static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1965
1966
  {
  	int ct;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
1967
1968
  
  	for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
b70432f73   Yuval Mintz   mroute*: Make mr_...
1969
  		if (mrt->vif_table[ct].dev == dev)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1970
1971
1972
1973
  			break;
  	}
  	return ct;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
1974
  static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1975
1976
  			   struct net_device *dev, struct sk_buff *skb,
  			   struct mfc6_cache *c)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1977
1978
1979
  {
  	int psend = -1;
  	int vif, ct;
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
1980
  	int true_vifi = ip6mr_find_vif(mrt, dev);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1981

494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1982
1983
1984
1985
  	vif = c->_c.mfc_parent;
  	c->_c.mfc_un.res.pkt++;
  	c->_c.mfc_un.res.bytes += skb->len;
  	c->_c.mfc_un.res.lastuse = jiffies;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
1986

494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1987
  	if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1988
  		struct mfc6_cache *cache_proxy;
40dc2ca3c   Fabian Frederick   ipv6: spelling s/...
1989
  		/* For an (*,G) entry, we only check that the incoming
660b26dc1   Nicolas Dichtel   mcast: add multic...
1990
1991
  		 * interface is part of the static tree.
  		 */
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1992
  		rcu_read_lock();
845c9a7ae   Yuval Mintz   ipmr, ip6mr: Unit...
1993
  		cache_proxy = mr_mfc_find_any_parent(mrt, vif);
660b26dc1   Nicolas Dichtel   mcast: add multic...
1994
  		if (cache_proxy &&
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
1995
  		    cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1996
  			rcu_read_unlock();
660b26dc1   Nicolas Dichtel   mcast: add multic...
1997
  			goto forward;
87c418bf1   Yuval Mintz   ip6mr: Align hash...
1998
1999
  		}
  		rcu_read_unlock();
660b26dc1   Nicolas Dichtel   mcast: add multic...
2000
  	}
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2001
2002
2003
  	/*
  	 * Wrong interface: drop packet and (maybe) send PIM assert.
  	 */
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2004
  	if (mrt->vif_table[vif].dev != dev) {
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2005
  		c->_c.mfc_un.res.wrong_if++;
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2006

6bd521433   Patrick McHardy   ipv6: ip6mr: move...
2007
  		if (true_vifi >= 0 && mrt->mroute_do_assert &&
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2008
2009
2010
2011
2012
  		    /* pimsm uses asserts, when switching from RPT to SPT,
  		       so that we cannot check that packet arrived on an oif.
  		       It is bad, but otherwise we would need to move pretty
  		       large chunk of pimd to kernel. Ough... --ANK
  		     */
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
2013
  		    (mrt->mroute_do_pim ||
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2014
  		     c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2015
  		    time_after(jiffies,
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2016
2017
2018
  			       c->_c.mfc_un.res.last_assert +
  			       MFC_ASSERT_THRESH)) {
  			c->_c.mfc_un.res.last_assert = jiffies;
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
2019
  			ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2020
2021
2022
  		}
  		goto dont_forward;
  	}
660b26dc1   Nicolas Dichtel   mcast: add multic...
2023
  forward:
b70432f73   Yuval Mintz   mroute*: Make mr_...
2024
2025
  	mrt->vif_table[vif].pkt_in++;
  	mrt->vif_table[vif].bytes_in += skb->len;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2026
2027
2028
2029
  
  	/*
  	 *	Forward the frame
  	 */
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2030
2031
  	if (ipv6_addr_any(&c->mf6c_origin) &&
  	    ipv6_addr_any(&c->mf6c_mcastgrp)) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
2032
  		if (true_vifi >= 0 &&
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2033
  		    true_vifi != c->_c.mfc_parent &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
2034
  		    ipv6_hdr(skb)->hop_limit >
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2035
  				c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
2036
2037
2038
2039
  			/* It's an (*,*) entry and the packet is not coming from
  			 * the upstream: forward the packet to the upstream
  			 * only.
  			 */
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2040
  			psend = c->_c.mfc_parent;
660b26dc1   Nicolas Dichtel   mcast: add multic...
2041
2042
2043
2044
  			goto last_forward;
  		}
  		goto dont_forward;
  	}
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2045
2046
  	for (ct = c->_c.mfc_un.res.maxvif - 1;
  	     ct >= c->_c.mfc_un.res.minvif; ct--) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
2047
  		/* For (*,G) entry, don't forward to the incoming interface */
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2048
2049
  		if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) &&
  		    ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2050
2051
2052
  			if (psend != -1) {
  				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
  				if (skb2)
f5c6dfdef   David Ahern   ip6mr: Drop mfc6_...
2053
  					ip6mr_forward2(net, mrt, skb2, psend);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2054
2055
2056
2057
  			}
  			psend = ct;
  		}
  	}
660b26dc1   Nicolas Dichtel   mcast: add multic...
2058
  last_forward:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2059
  	if (psend != -1) {
f5c6dfdef   David Ahern   ip6mr: Drop mfc6_...
2060
  		ip6mr_forward2(net, mrt, skb, psend);
2b52c3ada   Rami Rosen   ip6mr: change the...
2061
  		return;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2062
  	}
14fb64e1f   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2063
  dont_forward:
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2064
  	kfree_skb(skb);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
  }
  
  
  /*
   *	Multicast packets for forwarding arrive here
   */
  
  int ip6_mr_input(struct sk_buff *skb)
  {
  	struct mfc6_cache *cache;
8229efdae   Benjamin Thery   netns: ip6mr: ena...
2075
  	struct net *net = dev_net(skb->dev);
b70432f73   Yuval Mintz   mroute*: Make mr_...
2076
  	struct mr_table *mrt;
4c9483b2f   David S. Miller   ipv6: Convert to ...
2077
2078
2079
  	struct flowi6 fl6 = {
  		.flowi6_iif	= skb->dev->ifindex,
  		.flowi6_mark	= skb->mark,
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
2080
2081
  	};
  	int err;
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
  	struct net_device *dev;
  
  	/* skb->dev passed in is the master dev for vrfs.
  	 * Get the proper interface that does have a vif associated with it.
  	 */
  	dev = skb->dev;
  	if (netif_is_l3_master(skb->dev)) {
  		dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
  		if (!dev) {
  			kfree_skb(skb);
  			return -ENODEV;
  		}
  	}
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
2095

4c9483b2f   David S. Miller   ipv6: Convert to ...
2096
  	err = ip6mr_fib_lookup(net, &fl6, &mrt);
2015de5fe   Ben Greear   ipv6-multicast: F...
2097
2098
  	if (err < 0) {
  		kfree_skb(skb);
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
2099
  		return err;
2015de5fe   Ben Greear   ipv6-multicast: F...
2100
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2101
2102
  
  	read_lock(&mrt_lock);
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
2103
  	cache = ip6mr_cache_find(mrt,
8229efdae   Benjamin Thery   netns: ip6mr: ena...
2104
  				 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
63159f29b   Ian Morris   ipv6: coding styl...
2105
  	if (!cache) {
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2106
  		int vif = ip6mr_find_vif(mrt, dev);
660b26dc1   Nicolas Dichtel   mcast: add multic...
2107
2108
2109
2110
2111
2112
  
  		if (vif >= 0)
  			cache = ip6mr_cache_find_any(mrt,
  						     &ipv6_hdr(skb)->daddr,
  						     vif);
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2113
2114
2115
2116
  
  	/*
  	 *	No usable cache entry
  	 */
63159f29b   Ian Morris   ipv6: coding styl...
2117
  	if (!cache) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2118
  		int vif;
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2119
  		vif = ip6mr_find_vif(mrt, dev);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2120
  		if (vif >= 0) {
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2121
  			int err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2122
2123
2124
2125
2126
2127
2128
2129
  			read_unlock(&mrt_lock);
  
  			return err;
  		}
  		read_unlock(&mrt_lock);
  		kfree_skb(skb);
  		return -ENODEV;
  	}
e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2130
  	ip6_mr_forward(net, mrt, dev, skb, cache);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2131
2132
2133
2134
2135
  
  	read_unlock(&mrt_lock);
  
  	return 0;
  }
2cf750704   Nikolay Aleksandrov   ipmr, ip6mr: fix ...
2136
  int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
fd61c6ba3   David Ahern   net: ipv6: remove...
2137
  		    u32 portid)
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2138
2139
  {
  	int err;
b70432f73   Yuval Mintz   mroute*: Make mr_...
2140
  	struct mr_table *mrt;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2141
  	struct mfc6_cache *cache;
adf30907d   Eric Dumazet   net: skb->dst acc...
2142
  	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2143

d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
2144
  	mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
63159f29b   Ian Morris   ipv6: coding styl...
2145
  	if (!mrt)
d1db275dd   Patrick McHardy   ipv6: ip6mr: supp...
2146
  		return -ENOENT;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2147
  	read_lock(&mrt_lock);
6bd521433   Patrick McHardy   ipv6: ip6mr: move...
2148
  	cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
660b26dc1   Nicolas Dichtel   mcast: add multic...
2149
2150
2151
2152
2153
2154
2155
  	if (!cache && skb->dev) {
  		int vif = ip6mr_find_vif(mrt, skb->dev);
  
  		if (vif >= 0)
  			cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
  						     vif);
  	}
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2156
2157
2158
2159
2160
2161
  
  	if (!cache) {
  		struct sk_buff *skb2;
  		struct ipv6hdr *iph;
  		struct net_device *dev;
  		int vif;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2162
  		dev = skb->dev;
63159f29b   Ian Morris   ipv6: coding styl...
2163
  		if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
  			read_unlock(&mrt_lock);
  			return -ENODEV;
  		}
  
  		/* really correct? */
  		skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
  		if (!skb2) {
  			read_unlock(&mrt_lock);
  			return -ENOMEM;
  		}
2cf750704   Nikolay Aleksandrov   ipmr, ip6mr: fix ...
2174
  		NETLINK_CB(skb2).portid = portid;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
  		skb_reset_transport_header(skb2);
  
  		skb_put(skb2, sizeof(struct ipv6hdr));
  		skb_reset_network_header(skb2);
  
  		iph = ipv6_hdr(skb2);
  		iph->version = 0;
  		iph->priority = 0;
  		iph->flow_lbl[0] = 0;
  		iph->flow_lbl[1] = 0;
  		iph->flow_lbl[2] = 0;
  		iph->payload_len = 0;
  		iph->nexthdr = IPPROTO_NONE;
  		iph->hop_limit = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
2189
2190
  		iph->saddr = rt->rt6i_src.addr;
  		iph->daddr = rt->rt6i_dst.addr;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2191

e4a38c0c4   Patrick Ruddy   ipv6: add vrf tab...
2192
  		err = ip6mr_cache_unresolved(mrt, vif, skb2, dev);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2193
2194
2195
2196
  		read_unlock(&mrt_lock);
  
  		return err;
  	}
7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
2197
  	err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
2198
2199
2200
  	read_unlock(&mrt_lock);
  	return err;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
2201
  static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
f518338b1   Nicolas Dichtel   ip6mr: fix mfc no...
2202
2203
  			     u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
  			     int flags)
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2204
2205
2206
  {
  	struct nlmsghdr *nlh;
  	struct rtmsg *rtm;
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2207
  	int err;
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2208

f518338b1   Nicolas Dichtel   ip6mr: fix mfc no...
2209
  	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
63159f29b   Ian Morris   ipv6: coding styl...
2210
  	if (!nlh)
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2211
2212
2213
  		return -EMSGSIZE;
  
  	rtm = nlmsg_data(nlh);
193c1e478   Nicolas Dichtel   ip6mr: fix rtm_fa...
2214
  	rtm->rtm_family   = RTNL_FAMILY_IP6MR;
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2215
2216
2217
2218
  	rtm->rtm_dst_len  = 128;
  	rtm->rtm_src_len  = 128;
  	rtm->rtm_tos      = 0;
  	rtm->rtm_table    = mrt->id;
c78679e8f   David S. Miller   ipv6: Stop using ...
2219
2220
  	if (nla_put_u32(skb, RTA_TABLE, mrt->id))
  		goto nla_put_failure;
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2221
  	rtm->rtm_type = RTN_MULTICAST;
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2222
  	rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2223
  	if (c->_c.mfc_flags & MFC_STATIC)
9a68ac72a   Nicolas Dichtel   ipmr/ip6mr: repor...
2224
2225
2226
  		rtm->rtm_protocol = RTPROT_STATIC;
  	else
  		rtm->rtm_protocol = RTPROT_MROUTED;
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2227
  	rtm->rtm_flags    = 0;
930345ea6   Jiri Benc   netlink: implemen...
2228
2229
  	if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) ||
  	    nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp))
c78679e8f   David S. Miller   ipv6: Stop using ...
2230
  		goto nla_put_failure;
7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
2231
  	err = mr_fill_mroute(mrt, skb, &c->_c, rtm);
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2232
2233
  	/* do not break the dump if cache is unresolved */
  	if (err < 0 && err != -ENOENT)
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2234
  		goto nla_put_failure;
053c095a8   Johannes Berg   netlink: make nlm...
2235
2236
  	nlmsg_end(skb, nlh);
  	return 0;
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2237
2238
2239
2240
2241
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
2242
2243
2244
2245
2246
2247
2248
  static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
  			      u32 portid, u32 seq, struct mr_mfc *c,
  			      int cmd, int flags)
  {
  	return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c,
  				 cmd, flags);
  }
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
  static int mr6_msgsize(bool unresolved, int maxvif)
  {
  	size_t len =
  		NLMSG_ALIGN(sizeof(struct rtmsg))
  		+ nla_total_size(4)	/* RTA_TABLE */
  		+ nla_total_size(sizeof(struct in6_addr))	/* RTA_SRC */
  		+ nla_total_size(sizeof(struct in6_addr))	/* RTA_DST */
  		;
  
  	if (!unresolved)
  		len = len
  		      + nla_total_size(4)	/* RTA_IIF */
  		      + nla_total_size(0)	/* RTA_MULTIPATH */
  		      + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
  						/* RTA_MFC_STATS */
3d6b66c1d   Nicolas Dichtel   ip6mr: align RTA_...
2264
  		      + nla_total_size_64bit(sizeof(struct rta_mfc_stats))
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2265
2266
2267
2268
  		;
  
  	return len;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
2269
  static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2270
2271
2272
2273
2274
  			      int cmd)
  {
  	struct net *net = read_pnet(&mrt->net);
  	struct sk_buff *skb;
  	int err = -ENOBUFS;
494fff563   Yuval Mintz   ipmr, ip6mr: Make...
2275
  	skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2276
  			GFP_ATOMIC);
63159f29b   Ian Morris   ipv6: coding styl...
2277
  	if (!skb)
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2278
  		goto errout;
f518338b1   Nicolas Dichtel   ip6mr: fix mfc no...
2279
  	err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
812e44dd1   Nicolas Dichtel   ip6mr: advertise ...
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
  	if (err < 0)
  		goto errout;
  
  	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC);
  	return;
  
  errout:
  	kfree_skb(skb);
  	if (err < 0)
  		rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err);
  }
dd12d15c9   Julien Gomes   ip6mr: add netlin...
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
  static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
  {
  	size_t len =
  		NLMSG_ALIGN(sizeof(struct rtgenmsg))
  		+ nla_total_size(1)	/* IP6MRA_CREPORT_MSGTYPE */
  		+ nla_total_size(4)	/* IP6MRA_CREPORT_MIF_ID */
  					/* IP6MRA_CREPORT_SRC_ADDR */
  		+ nla_total_size(sizeof(struct in6_addr))
  					/* IP6MRA_CREPORT_DST_ADDR */
  		+ nla_total_size(sizeof(struct in6_addr))
  					/* IP6MRA_CREPORT_PKT */
  		+ nla_total_size(payloadlen)
  		;
  
  	return len;
  }
b70432f73   Yuval Mintz   mroute*: Make mr_...
2307
  static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
dd12d15c9   Julien Gomes   ip6mr: add netlin...
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
  {
  	struct net *net = read_pnet(&mrt->net);
  	struct nlmsghdr *nlh;
  	struct rtgenmsg *rtgenm;
  	struct mrt6msg *msg;
  	struct sk_buff *skb;
  	struct nlattr *nla;
  	int payloadlen;
  
  	payloadlen = pkt->len - sizeof(struct mrt6msg);
  	msg = (struct mrt6msg *)skb_transport_header(pkt);
  
  	skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC);
  	if (!skb)
  		goto errout;
  
  	nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT,
  			sizeof(struct rtgenmsg), 0);
  	if (!nlh)
  		goto errout;
  	rtgenm = nlmsg_data(nlh);
  	rtgenm->rtgen_family = RTNL_FAMILY_IP6MR;
  	if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) ||
  	    nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) ||
  	    nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR,
  			     &msg->im6_src) ||
  	    nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR,
  			     &msg->im6_dst))
  		goto nla_put_failure;
  
  	nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen);
  	if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg),
  				  nla_data(nla), payloadlen))
  		goto nla_put_failure;
  
  	nlmsg_end(skb, nlh);
  
  	rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC);
  	return;
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  errout:
  	kfree_skb(skb);
  	rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
  }
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2354
2355
  static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
  {
e8ba330ac   David Ahern   rtnetlink: Update...
2356
  	const struct nlmsghdr *nlh = cb->nlh;
4724676d5   David Ahern   net: Add struct f...
2357
  	struct fib_dump_filter filter = {};
cb167893f   David Ahern   net: Plumb suppor...
2358
  	int err;
e8ba330ac   David Ahern   rtnetlink: Update...
2359
2360
  
  	if (cb->strict_check) {
4724676d5   David Ahern   net: Add struct f...
2361
  		err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
effe67926   David Ahern   net: Enable kerne...
2362
  					    &filter, cb);
e8ba330ac   David Ahern   rtnetlink: Update...
2363
2364
2365
  		if (err < 0)
  			return err;
  	}
cb167893f   David Ahern   net: Plumb suppor...
2366
2367
2368
2369
2370
  	if (filter.table_id) {
  		struct mr_table *mrt;
  
  		mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
  		if (!mrt) {
41b4bd986   Sabrina Dubroca   net: don't return...
2371
  			if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR)
ae677bbb4   David Ahern   net: Don't return...
2372
  				return skb->len;
cb167893f   David Ahern   net: Plumb suppor...
2373
2374
2375
2376
2377
2378
2379
  			NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
  			return -ENOENT;
  		}
  		err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
  				    &mfc_unres_lock, &filter);
  		return skb->len ? : err;
  	}
7b0db8573   Yuval Mintz   ipmr, ip6mr: Unit...
2380
  	return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
cb167893f   David Ahern   net: Plumb suppor...
2381
  				_ip6mr_fill_mroute, &mfc_unres_lock, &filter);
5b285cac3   Patrick McHardy   ipv6: ip6mr: add ...
2382
  }