Blame view

net/ipv4/ipmr.c 63.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *	IP multicast routing support for mrouted 3.6/3.8
   *
113aa838e   Alan Cox   net: Rationalise ...
4
   *		(c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
   *	  Linux Consultancy and Custom Driver Development
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
21
22
23
24
   *	Fixes:
   *	Michael Chastain	:	Incorrect size of copying.
   *	Alan Cox		:	Added the cache manager code
   *	Alan Cox		:	Fixed the clone/copy bug and device race.
   *	Mike McLagan		:	Routing by source
   *	Malcolm Beattie		:	Buffer handling fixes.
   *	Alexey Kuznetsov	:	Double buffer free and other fixes.
   *	SVR Anand		:	Fixed several multicast bugs and problems.
   *	Alexey Kuznetsov	:	Status, optimisations and more.
   *	Brad Parker		:	Better behaviour on mrouted upcall
   *					overflow.
   *      Carlos Picoto           :       PIMv1 Support
   *	Pavlin Ivanov Radoslavov:	PIMv2 Registers must checksum only PIM header
f77f13e22   Gilles Espinasse   Fix comment and K...
25
   *					Relax this requirement to work with older peers.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
  #include <asm/uaccess.h>
  #include <linux/types.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
30
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  #include <linux/errno.h>
  #include <linux/timer.h>
  #include <linux/mm.h>
  #include <linux/kernel.h>
  #include <linux/fcntl.h>
  #include <linux/stat.h>
  #include <linux/socket.h>
  #include <linux/in.h>
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/mroute.h>
  #include <linux/init.h>
46f25dffb   Kris Katterjohn   [NET]: Change 150...
47
  #include <linux/if_ether.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
48
  #include <linux/slab.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
49
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
  #include <net/ip.h>
  #include <net/protocol.h>
  #include <linux/skbuff.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
53
  #include <net/route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
  #include <net/sock.h>
  #include <net/icmp.h>
  #include <net/udp.h>
  #include <net/raw.h>
  #include <linux/notifier.h>
  #include <linux/if_arp.h>
  #include <linux/netfilter_ipv4.h>
709b46e8d   Eric W. Biederman   net: Add compat i...
61
  #include <linux/compat.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
62
  #include <linux/export.h>
c54419321   Pravin B Shelar   GRE: Refactor GRE...
63
  #include <net/ip_tunnels.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #include <net/checksum.h>
dc5fc579b   Arnaldo Carvalho de Melo   [NETLINK]: Use nl...
65
  #include <net/netlink.h>
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
66
  #include <net/fib_rules.h>
d67b8c616   Nicolas Dichtel   netconf: advertis...
67
  #include <linux/netconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
  
  #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
  #define CONFIG_IP_PIMSM	1
  #endif
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
72
  struct mr_table {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
73
  	struct list_head	list;
8de53dfbf   Patrick McHardy   ipv4: ipmr: fix N...
74
75
76
  #ifdef CONFIG_NET_NS
  	struct net		*net;
  #endif
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
77
  	u32			id;
4c9687098   Eric Dumazet   ipmr: RCU convers...
78
  	struct sock __rcu	*mroute_sk;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
79
80
81
82
83
84
  	struct timer_list	ipmr_expire_timer;
  	struct list_head	mfc_unres_queue;
  	struct list_head	mfc_cache_array[MFC_LINES];
  	struct vif_device	vif_table[MAXVIFS];
  	int			maxvif;
  	atomic_t		cache_resolve_queue_len;
53d6841d2   Joe Perches   ipv4/ipmr and ipv...
85
86
  	bool			mroute_do_assert;
  	bool			mroute_do_pim;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
87
88
89
90
  #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
  	int			mroute_reg_vif_num;
  #endif
  };
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
91
92
93
94
95
96
97
  struct ipmr_rule {
  	struct fib_rule		common;
  };
  
  struct ipmr_result {
  	struct mr_table		*mrt;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  /* Big lock, protecting vif table, mrt cache and mroute socket state.
a8cb16dd9   Eric Dumazet   ipmr: cleanups
99
   * Note that the changes are semaphored via rtnl_lock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
   */
  
  static DEFINE_RWLOCK(mrt_lock);
  
  /*
   *	Multicast router control variables
   */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
107
  #define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
  
  /* Special spinlock for queue of unresolved entries */
  static DEFINE_SPINLOCK(mfc_unres_lock);
  
  /* We return to original Alan's scheme. Hash table of resolved
a8cb16dd9   Eric Dumazet   ipmr: cleanups
113
114
115
116
117
   * 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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
   */
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
119
  static struct kmem_cache *mrt_cachep __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
121
  static struct mr_table *ipmr_new_table(struct net *net, u32 id);
acbb219d5   Francesco Ruggeri   net: ipv4: ipmr_e...
122
  static void ipmr_free_table(struct mr_table *mrt);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
123
124
125
126
  static int ip_mr_forward(struct net *net, struct mr_table *mrt,
  			 struct sk_buff *skb, struct mfc_cache *cache,
  			 int local);
  static int ipmr_cache_report(struct mr_table *mrt,
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
127
  			     struct sk_buff *pkt, vifi_t vifi, int assert);
cb6a4e461   Patrick McHardy   net: ipmr: add su...
128
129
  static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
  			      struct mfc_cache *c, struct rtmsg *rtm);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
130
131
  static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
  				 int cmd);
acbb219d5   Francesco Ruggeri   net: ipv4: ipmr_e...
132
  static void mroute_clean_tables(struct mr_table *mrt);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  static void ipmr_expire_process(unsigned long arg);
  
  #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
  #define ipmr_for_each_table(mrt, net) \
  	list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list)
  
  static struct mr_table *ipmr_get_table(struct net *net, u32 id)
  {
  	struct mr_table *mrt;
  
  	ipmr_for_each_table(mrt, net) {
  		if (mrt->id == id)
  			return mrt;
  	}
  	return NULL;
  }
da91981be   David S. Miller   ipv4: Use flowi4 ...
149
  static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
150
151
152
153
154
  			   struct mr_table **mrt)
  {
  	struct ipmr_result res;
  	struct fib_lookup_arg arg = { .result = &res, };
  	int err;
da91981be   David S. Miller   ipv4: Use flowi4 ...
155
156
  	err = fib_rules_lookup(net->ipv4.mr_rules_ops,
  			       flowi4_to_flowi(flp4), 0, &arg);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
157
158
159
160
161
162
163
164
165
166
167
  	if (err < 0)
  		return err;
  	*mrt = res.mrt;
  	return 0;
  }
  
  static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
  			    int flags, struct fib_lookup_arg *arg)
  {
  	struct ipmr_result *res = arg->result;
  	struct mr_table *mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  	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;
  	}
  
  	mrt = ipmr_get_table(rule->fr_net, rule->table);
  	if (mrt == NULL)
  		return -EAGAIN;
  	res->mrt = mrt;
  	return 0;
  }
  
  static int ipmr_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
  {
  	return 1;
  }
  
  static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = {
  	FRA_GENERIC_POLICY,
  };
  
  static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
  			       struct fib_rule_hdr *frh, struct nlattr **tb)
  {
  	return 0;
  }
  
  static int ipmr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
  			     struct nlattr **tb)
  {
  	return 1;
  }
  
  static int ipmr_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...
217
  static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = {
25239cee7   Patrick McHardy   net: rtnetlink: d...
218
  	.family		= RTNL_FAMILY_IPMR,
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  	.rule_size	= sizeof(struct ipmr_rule),
  	.addr_size	= sizeof(u32),
  	.action		= ipmr_rule_action,
  	.match		= ipmr_rule_match,
  	.configure	= ipmr_rule_configure,
  	.compare	= ipmr_rule_compare,
  	.default_pref	= fib_default_rule_pref,
  	.fill		= ipmr_rule_fill,
  	.nlgroup	= RTNLGRP_IPV4_RULE,
  	.policy		= ipmr_rule_policy,
  	.owner		= THIS_MODULE,
  };
  
  static int __net_init ipmr_rules_init(struct net *net)
  {
  	struct fib_rules_ops *ops;
  	struct mr_table *mrt;
  	int err;
  
  	ops = fib_rules_register(&ipmr_rules_ops_template, net);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  
  	INIT_LIST_HEAD(&net->ipv4.mr_tables);
  
  	mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
  	if (mrt == NULL) {
  		err = -ENOMEM;
  		goto err1;
  	}
  
  	err = fib_default_rule_add(ops, 0x7fff, RT_TABLE_DEFAULT, 0);
  	if (err < 0)
  		goto err2;
  
  	net->ipv4.mr_rules_ops = ops;
  	return 0;
  
  err2:
  	kfree(mrt);
  err1:
  	fib_rules_unregister(ops);
  	return err;
  }
  
  static void __net_exit ipmr_rules_exit(struct net *net)
  {
  	struct mr_table *mrt, *next;
035320d54   Eric Dumazet   ipmr: dont corrup...
267
268
  	list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
  		list_del(&mrt->list);
acbb219d5   Francesco Ruggeri   net: ipv4: ipmr_e...
269
  		ipmr_free_table(mrt);
035320d54   Eric Dumazet   ipmr: dont corrup...
270
  	}
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
271
272
273
274
275
276
277
278
279
280
  	fib_rules_unregister(net->ipv4.mr_rules_ops);
  }
  #else
  #define ipmr_for_each_table(mrt, net) \
  	for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
  
  static struct mr_table *ipmr_get_table(struct net *net, u32 id)
  {
  	return net->ipv4.mrt;
  }
da91981be   David S. Miller   ipv4: Use flowi4 ...
281
  static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  			   struct mr_table **mrt)
  {
  	*mrt = net->ipv4.mrt;
  	return 0;
  }
  
  static int __net_init ipmr_rules_init(struct net *net)
  {
  	net->ipv4.mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
  	return net->ipv4.mrt ? 0 : -ENOMEM;
  }
  
  static void __net_exit ipmr_rules_exit(struct net *net)
  {
acbb219d5   Francesco Ruggeri   net: ipv4: ipmr_e...
296
  	ipmr_free_table(net->ipv4.mrt);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
297
298
299
300
301
302
303
  }
  #endif
  
  static struct mr_table *ipmr_new_table(struct net *net, u32 id)
  {
  	struct mr_table *mrt;
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
305
306
307
308
309
310
311
  	mrt = ipmr_get_table(net, id);
  	if (mrt != NULL)
  		return mrt;
  
  	mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
  	if (mrt == NULL)
  		return NULL;
8de53dfbf   Patrick McHardy   ipv4: ipmr: fix N...
312
  	write_pnet(&mrt->net, net);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  	mrt->id = id;
  
  	/* Forwarding cache */
  	for (i = 0; i < MFC_LINES; i++)
  		INIT_LIST_HEAD(&mrt->mfc_cache_array[i]);
  
  	INIT_LIST_HEAD(&mrt->mfc_unres_queue);
  
  	setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
  		    (unsigned long)mrt);
  
  #ifdef CONFIG_IP_PIMSM
  	mrt->mroute_reg_vif_num = -1;
  #endif
  #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
  	list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables);
  #endif
  	return mrt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

acbb219d5   Francesco Ruggeri   net: ipv4: ipmr_e...
333
334
335
336
337
338
  static void ipmr_free_table(struct mr_table *mrt)
  {
  	del_timer_sync(&mrt->ipmr_expire_timer);
  	mroute_clean_tables(mrt);
  	kfree(mrt);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
d607032db   Wang Chen   ipv4: Check retur...
340
341
  static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
  {
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
342
  	struct net *net = dev_net(dev);
d607032db   Wang Chen   ipv4: Check retur...
343
  	dev_close(dev);
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
344
  	dev = __dev_get_by_name(net, "tunl0");
d607032db   Wang Chen   ipv4: Check retur...
345
  	if (dev) {
5bc3eb7e2   Stephen Hemminger   ip: convert to ne...
346
  		const struct net_device_ops *ops = dev->netdev_ops;
d607032db   Wang Chen   ipv4: Check retur...
347
  		struct ifreq ifr;
d607032db   Wang Chen   ipv4: Check retur...
348
349
350
351
352
353
354
355
356
357
  		struct ip_tunnel_parm p;
  
  		memset(&p, 0, sizeof(p));
  		p.iph.daddr = v->vifc_rmt_addr.s_addr;
  		p.iph.saddr = v->vifc_lcl_addr.s_addr;
  		p.iph.version = 4;
  		p.iph.ihl = 5;
  		p.iph.protocol = IPPROTO_IPIP;
  		sprintf(p.name, "dvmrp%d", v->vifc_vifi);
  		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
5bc3eb7e2   Stephen Hemminger   ip: convert to ne...
358
359
360
361
362
363
364
  		if (ops->ndo_do_ioctl) {
  			mm_segment_t oldfs = get_fs();
  
  			set_fs(KERNEL_DS);
  			ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
  			set_fs(oldfs);
  		}
d607032db   Wang Chen   ipv4: Check retur...
365
366
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  static
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
368
  struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
  {
  	struct net_device  *dev;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
371
  	dev = __dev_get_by_name(net, "tunl0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  
  	if (dev) {
5bc3eb7e2   Stephen Hemminger   ip: convert to ne...
374
  		const struct net_device_ops *ops = dev->netdev_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
  		int err;
  		struct ifreq ifr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
383
384
385
386
  		struct ip_tunnel_parm p;
  		struct in_device  *in_dev;
  
  		memset(&p, 0, sizeof(p));
  		p.iph.daddr = v->vifc_rmt_addr.s_addr;
  		p.iph.saddr = v->vifc_lcl_addr.s_addr;
  		p.iph.version = 4;
  		p.iph.ihl = 5;
  		p.iph.protocol = IPPROTO_IPIP;
  		sprintf(p.name, "dvmrp%d", v->vifc_vifi);
ba93ef746   Stephen Hemminger   [IPV4]: ipmr spar...
387
  		ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

5bc3eb7e2   Stephen Hemminger   ip: convert to ne...
389
390
391
392
393
394
  		if (ops->ndo_do_ioctl) {
  			mm_segment_t oldfs = get_fs();
  
  			set_fs(KERNEL_DS);
  			err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
  			set_fs(oldfs);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
395
  		} else {
5bc3eb7e2   Stephen Hemminger   ip: convert to ne...
396
  			err = -EOPNOTSUPP;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
397
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  		dev = NULL;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
399
400
  		if (err == 0 &&
  		    (dev = __dev_get_by_name(net, p.name)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  			dev->flags |= IFF_MULTICAST;
e5ed63991   Herbert Xu   [IPV4]: Replace _...
402
  			in_dev = __in_dev_get_rtnl(dev);
71e27da96   Herbert Xu   [IPV4]: Restore o...
403
  			if (in_dev == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
  				goto failure;
71e27da96   Herbert Xu   [IPV4]: Restore o...
405
406
407
  
  			ipv4_devconf_setall(in_dev);
  			IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
  
  			if (dev_open(dev))
  				goto failure;
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
411
  			dev_hold(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  		}
  	}
  	return dev;
  
  failure:
  	/* allow the register to be completed before unregistering. */
  	rtnl_unlock();
  	rtnl_lock();
  
  	unregister_netdevice(dev);
  	return NULL;
  }
  
  #ifdef CONFIG_IP_PIMSM
6fef4c0c8   Stephen Hemminger   netdev: convert p...
426
  static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  {
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
428
  	struct net *net = dev_net(dev);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
429
  	struct mr_table *mrt;
da91981be   David S. Miller   ipv4: Use flowi4 ...
430
431
432
433
  	struct flowi4 fl4 = {
  		.flowi4_oif	= dev->ifindex,
  		.flowi4_iif	= skb->skb_iif,
  		.flowi4_mark	= skb->mark,
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
434
435
  	};
  	int err;
da91981be   David S. Miller   ipv4: Use flowi4 ...
436
  	err = ipmr_fib_lookup(net, &fl4, &mrt);
e40dbc51f   Ben Greear   ipmr: Don't leak ...
437
438
  	if (err < 0) {
  		kfree_skb(skb);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
439
  		return err;
e40dbc51f   Ben Greear   ipmr: Don't leak ...
440
  	}
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
441

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	read_lock(&mrt_lock);
cf3677ae1   Pavel Emelyanov   ipmr: Use on-devi...
443
444
  	dev->stats.tx_bytes += skb->len;
  	dev->stats.tx_packets++;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
445
  	ipmr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, IGMPMSG_WHOLEPKT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
  	read_unlock(&mrt_lock);
  	kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
448
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  }
007c3838d   Stephen Hemminger   ipmr: convert ipm...
450
451
452
  static const struct net_device_ops reg_vif_netdev_ops = {
  	.ndo_start_xmit	= reg_vif_xmit,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
  static void reg_vif_setup(struct net_device *dev)
  {
  	dev->type		= ARPHRD_PIMREG;
46f25dffb   Kris Katterjohn   [NET]: Change 150...
456
  	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr) - 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	dev->flags		= IFF_NOARP;
007c3838d   Stephen Hemminger   ipmr: convert ipm...
458
  	dev->netdev_ops		= &reg_vif_netdev_ops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  	dev->destructor		= free_netdev;
403dbb97f   Tom Goff   PIM-SM: namespace...
460
  	dev->features		|= NETIF_F_NETNS_LOCAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  }
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
462
  static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
  {
  	struct net_device *dev;
  	struct in_device *in_dev;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
466
  	char name[IFNAMSIZ];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
468
469
470
471
  	if (mrt->id == RT_TABLE_DEFAULT)
  		sprintf(name, "pimreg");
  	else
  		sprintf(name, "pimreg%u", mrt->id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
473
  	dev = alloc_netdev(0, name, reg_vif_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
  
  	if (dev == NULL)
  		return NULL;
403dbb97f   Tom Goff   PIM-SM: namespace...
477
  	dev_net_set(dev, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
482
  	if (register_netdevice(dev)) {
  		free_netdev(dev);
  		return NULL;
  	}
  	dev->iflink = 0;
71e27da96   Herbert Xu   [IPV4]: Restore o...
483
  	rcu_read_lock();
a8cb16dd9   Eric Dumazet   ipmr: cleanups
484
485
  	in_dev = __in_dev_get_rcu(dev);
  	if (!in_dev) {
71e27da96   Herbert Xu   [IPV4]: Restore o...
486
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  		goto failure;
71e27da96   Herbert Xu   [IPV4]: Restore o...
488
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489

71e27da96   Herbert Xu   [IPV4]: Restore o...
490
491
492
  	ipv4_devconf_setall(in_dev);
  	IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
495
  
  	if (dev_open(dev))
  		goto failure;
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
496
  	dev_hold(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
504
505
506
507
  	return dev;
  
  failure:
  	/* allow the register to be completed before unregistering. */
  	rtnl_unlock();
  	rtnl_lock();
  
  	unregister_netdevice(dev);
  	return NULL;
  }
  #endif
2c53040f0   Ben Hutchings   net: Fix (nearly-...
508
509
  /**
   *	vif_delete - Delete a VIF entry
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
510
   *	@notify: Set to 1, if the caller is a notifier_call
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
512

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
513
  static int vif_delete(struct mr_table *mrt, int vifi, int notify,
d17fa6fa8   Eric Dumazet   ipmr: Optimize mu...
514
  		      struct list_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
  {
  	struct vif_device *v;
  	struct net_device *dev;
  	struct in_device *in_dev;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
519
  	if (vifi < 0 || vifi >= mrt->maxvif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  		return -EADDRNOTAVAIL;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
521
  	v = &mrt->vif_table[vifi];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
528
529
530
531
532
  
  	write_lock_bh(&mrt_lock);
  	dev = v->dev;
  	v->dev = NULL;
  
  	if (!dev) {
  		write_unlock_bh(&mrt_lock);
  		return -EADDRNOTAVAIL;
  	}
  
  #ifdef CONFIG_IP_PIMSM
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
533
534
  	if (vifi == mrt->mroute_reg_vif_num)
  		mrt->mroute_reg_vif_num = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  #endif
a8cb16dd9   Eric Dumazet   ipmr: cleanups
536
  	if (vifi + 1 == mrt->maxvif) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		int tmp;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
538
539
  
  		for (tmp = vifi - 1; tmp >= 0; tmp--) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
540
  			if (VIF_EXISTS(mrt, tmp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
  				break;
  		}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
543
  		mrt->maxvif = tmp+1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
  	}
  
  	write_unlock_bh(&mrt_lock);
  
  	dev_set_allmulti(dev, -1);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
549
550
  	in_dev = __in_dev_get_rtnl(dev);
  	if (in_dev) {
42f811b8b   Herbert Xu   [IPV4]: Convert I...
551
  		IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
d67b8c616   Nicolas Dichtel   netconf: advertis...
552
553
554
  		inet_netconf_notify_devconf(dev_net(dev),
  					    NETCONFA_MC_FORWARDING,
  					    dev->ifindex, &in_dev->cnf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  		ip_rt_multicast_event(in_dev);
  	}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
557
  	if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify)
d17fa6fa8   Eric Dumazet   ipmr: Optimize mu...
558
  		unregister_netdevice_queue(dev, head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
  
  	dev_put(dev);
  	return 0;
  }
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
563
  static void ipmr_cache_free_rcu(struct rcu_head *head)
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
564
  {
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
565
  	struct mfc_cache *c = container_of(head, struct mfc_cache, rcu);
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
566
567
  	kmem_cache_free(mrt_cachep, c);
  }
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
568
569
570
571
  static inline void ipmr_cache_free(struct mfc_cache *c)
  {
  	call_rcu(&c->rcu, ipmr_cache_free_rcu);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  /* Destroy an unresolved cache entry, killing queued skbs
a8cb16dd9   Eric Dumazet   ipmr: cleanups
573
   * and reporting error to netlink readers.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
   */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
575
  static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  {
8de53dfbf   Patrick McHardy   ipv4: ipmr: fix N...
577
  	struct net *net = read_pnet(&mrt->net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  	struct sk_buff *skb;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
579
  	struct nlmsgerr *e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
581
  	atomic_dec(&mrt->cache_resolve_queue_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

c354e1246   Jianjun Kong   net: clean up net...
583
  	while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
584
  		if (ip_hdr(skb)->version == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
  			nlh->nlmsg_type = NLMSG_ERROR;
573ce260b   Hong zhi guo   net-next: replace...
587
  			nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  			skb_trim(skb, nlh->nlmsg_len);
573ce260b   Hong zhi guo   net-next: replace...
589
  			e = nlmsg_data(nlh);
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
590
591
  			e->error = -ETIMEDOUT;
  			memset(&e->msg, 0, sizeof(e->msg));
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
592

15e473046   Eric W. Biederman   netlink: Rename p...
593
  			rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
594
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
  			kfree_skb(skb);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
596
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  	}
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
598
  	ipmr_cache_free(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  }
e258beb22   Patrick McHardy   ipv4: ipmr: move ...
600
  /* Timer process for the unresolved queue. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

e258beb22   Patrick McHardy   ipv4: ipmr: move ...
602
  static void ipmr_expire_process(unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
604
  	struct mr_table *mrt = (struct mr_table *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  	unsigned long now;
  	unsigned long expires;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
607
  	struct mfc_cache *c, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
  
  	if (!spin_trylock(&mfc_unres_lock)) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
610
  		mod_timer(&mrt->ipmr_expire_timer, jiffies+HZ/10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
  		return;
  	}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
613
  	if (list_empty(&mrt->mfc_unres_queue))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
  		goto out;
  
  	now = jiffies;
  	expires = 10*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
619
  	list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
  		if (time_after(c->mfc_un.unres.expires, now)) {
  			unsigned long interval = c->mfc_un.unres.expires - now;
  			if (interval < expires)
  				expires = interval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
  			continue;
  		}
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
626
  		list_del(&c->list);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
627
  		mroute_netlink_event(mrt, c, RTM_DELROUTE);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
628
  		ipmr_destroy_unres(mrt, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
630
631
  	if (!list_empty(&mrt->mfc_unres_queue))
  		mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
637
  
  out:
  	spin_unlock(&mfc_unres_lock);
  }
  
  /* Fill oifs list. It is called under write locked mrt_lock. */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
638
  static void ipmr_update_thresholds(struct mr_table *mrt, struct mfc_cache *cache,
d658f8a0e   Patrick McHardy   ipv4: ipmr: remov...
639
  				   unsigned char *ttls)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
  {
  	int vifi;
  
  	cache->mfc_un.res.minvif = MAXVIFS;
  	cache->mfc_un.res.maxvif = 0;
  	memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
646
647
  	for (vifi = 0; vifi < mrt->maxvif; vifi++) {
  		if (VIF_EXISTS(mrt, vifi) &&
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
648
  		    ttls[vifi] && ttls[vifi] < 255) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
656
  			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;
  		}
  	}
  }
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
657
658
  static int vif_add(struct net *net, struct mr_table *mrt,
  		   struct vifctl *vifc, int mrtsock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
  {
  	int vifi = vifc->vifc_vifi;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
661
  	struct vif_device *v = &mrt->vif_table[vifi];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
  	struct net_device *dev;
  	struct in_device *in_dev;
d607032db   Wang Chen   ipv4: Check retur...
664
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  
  	/* Is vif busy ? */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
667
  	if (VIF_EXISTS(mrt, vifi))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
673
674
675
676
  		return -EADDRINUSE;
  
  	switch (vifc->vifc_flags) {
  #ifdef CONFIG_IP_PIMSM
  	case VIFF_REGISTER:
  		/*
  		 * Special Purpose VIF in PIM
  		 * All the packets will be sent to the daemon
  		 */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
677
  		if (mrt->mroute_reg_vif_num >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  			return -EADDRINUSE;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
679
  		dev = ipmr_reg_vif(net, mrt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
  		if (!dev)
  			return -ENOBUFS;
d607032db   Wang Chen   ipv4: Check retur...
682
683
684
  		err = dev_set_allmulti(dev, 1);
  		if (err) {
  			unregister_netdevice(dev);
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
685
  			dev_put(dev);
d607032db   Wang Chen   ipv4: Check retur...
686
687
  			return err;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
689
  		break;
  #endif
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
690
  	case VIFF_TUNNEL:
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
691
  		dev = ipmr_new_tunnel(net, vifc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  		if (!dev)
  			return -ENOBUFS;
d607032db   Wang Chen   ipv4: Check retur...
694
695
696
  		err = dev_set_allmulti(dev, 1);
  		if (err) {
  			ipmr_del_tunnel(dev, vifc);
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
697
  			dev_put(dev);
d607032db   Wang Chen   ipv4: Check retur...
698
699
  			return err;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  		break;
ee5e81f00   Ilia K   add vif using loc...
701
702
  
  	case VIFF_USE_IFINDEX:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
  	case 0:
ee5e81f00   Ilia K   add vif using loc...
704
705
  		if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
  			dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
95ae6b228   Eric Dumazet   ipv4: ip_ptr clea...
706
  			if (dev && __in_dev_get_rtnl(dev) == NULL) {
ee5e81f00   Ilia K   add vif using loc...
707
708
709
  				dev_put(dev);
  				return -EADDRNOTAVAIL;
  			}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
710
  		} else {
ee5e81f00   Ilia K   add vif using loc...
711
  			dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
712
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
  		if (!dev)
  			return -EADDRNOTAVAIL;
d607032db   Wang Chen   ipv4: Check retur...
715
  		err = dev_set_allmulti(dev, 1);
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
716
717
  		if (err) {
  			dev_put(dev);
d607032db   Wang Chen   ipv4: Check retur...
718
  			return err;
7dc00c82c   Wang Chen   ipv4: Fix ipmr un...
719
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
  		break;
  	default:
  		return -EINVAL;
  	}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
724
725
  	in_dev = __in_dev_get_rtnl(dev);
  	if (!in_dev) {
d0490cfdf   Dan Carpenter   ipmr: missing dev...
726
  		dev_put(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  		return -EADDRNOTAVAIL;
d0490cfdf   Dan Carpenter   ipmr: missing dev...
728
  	}
42f811b8b   Herbert Xu   [IPV4]: Convert I...
729
  	IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
d67b8c616   Nicolas Dichtel   netconf: advertis...
730
731
  	inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING, dev->ifindex,
  				    &in_dev->cnf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
  	ip_rt_multicast_event(in_dev);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
733
  	/* Fill in the VIF structures */
c354e1246   Jianjun Kong   net: clean up net...
734
735
736
737
  	v->rate_limit = vifc->vifc_rate_limit;
  	v->local = vifc->vifc_lcl_addr.s_addr;
  	v->remote = vifc->vifc_rmt_addr.s_addr;
  	v->flags = vifc->vifc_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
739
  	if (!mrtsock)
  		v->flags |= VIFF_STATIC;
c354e1246   Jianjun Kong   net: clean up net...
740
  	v->threshold = vifc->vifc_threshold;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
744
745
  	v->bytes_in = 0;
  	v->bytes_out = 0;
  	v->pkt_in = 0;
  	v->pkt_out = 0;
  	v->link = dev->ifindex;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
746
  	if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
  		v->link = dev->iflink;
  
  	/* And finish update writing critical data */
  	write_lock_bh(&mrt_lock);
c354e1246   Jianjun Kong   net: clean up net...
751
  	v->dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  #ifdef CONFIG_IP_PIMSM
a8cb16dd9   Eric Dumazet   ipmr: cleanups
753
  	if (v->flags & VIFF_REGISTER)
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
754
  		mrt->mroute_reg_vif_num = vifi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  #endif
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
756
757
  	if (vifi+1 > mrt->maxvif)
  		mrt->maxvif = vifi+1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
  	write_unlock_bh(&mrt_lock);
  	return 0;
  }
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
761
  /* called with rcu_read_lock() */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
762
  static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
763
764
  					 __be32 origin,
  					 __be32 mcastgrp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  {
c354e1246   Jianjun Kong   net: clean up net...
766
  	int line = MFC_HASH(mcastgrp, origin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  	struct mfc_cache *c;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
768
  	list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list) {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
769
770
  		if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
  			return c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	}
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
772
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  }
660b26dc1   Nicolas Dichtel   mcast: add multic...
774
775
776
777
  /* Look for a (*,*,oif) entry */
  static struct mfc_cache *ipmr_cache_find_any_parent(struct mr_table *mrt,
  						    int vifi)
  {
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
778
  	int line = MFC_HASH(htonl(INADDR_ANY), htonl(INADDR_ANY));
660b26dc1   Nicolas Dichtel   mcast: add multic...
779
780
781
  	struct mfc_cache *c;
  
  	list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
782
783
  		if (c->mfc_origin == htonl(INADDR_ANY) &&
  		    c->mfc_mcastgrp == htonl(INADDR_ANY) &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
784
785
786
787
788
789
790
791
792
793
  		    c->mfc_un.res.ttls[vifi] < 255)
  			return c;
  
  	return NULL;
  }
  
  /* Look for a (*,G) entry */
  static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt,
  					     __be32 mcastgrp, int vifi)
  {
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
794
  	int line = MFC_HASH(mcastgrp, htonl(INADDR_ANY));
660b26dc1   Nicolas Dichtel   mcast: add multic...
795
  	struct mfc_cache *c, *proxy;
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
796
  	if (mcastgrp == htonl(INADDR_ANY))
660b26dc1   Nicolas Dichtel   mcast: add multic...
797
798
799
  		goto skip;
  
  	list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
800
  		if (c->mfc_origin == htonl(INADDR_ANY) &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  		    c->mfc_mcastgrp == mcastgrp) {
  			if (c->mfc_un.res.ttls[vifi] < 255)
  				return c;
  
  			/* It's ok if the vifi is part of the static tree */
  			proxy = ipmr_cache_find_any_parent(mrt,
  							   c->mfc_parent);
  			if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
  				return c;
  		}
  
  skip:
  	return ipmr_cache_find_any_parent(mrt, vifi);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
  /*
   *	Allocate a multicast cache entry
   */
d658f8a0e   Patrick McHardy   ipv4: ipmr: remov...
818
  static struct mfc_cache *ipmr_cache_alloc(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  {
c354e1246   Jianjun Kong   net: clean up net...
820
  	struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
821
822
823
  
  	if (c)
  		c->mfc_un.res.minvif = MAXVIFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
  	return c;
  }
d658f8a0e   Patrick McHardy   ipv4: ipmr: remov...
826
  static struct mfc_cache *ipmr_cache_alloc_unres(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  {
c354e1246   Jianjun Kong   net: clean up net...
828
  	struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
829
830
831
832
833
  
  	if (c) {
  		skb_queue_head_init(&c->mfc_un.unres.unresolved);
  		c->mfc_un.unres.expires = jiffies + 10*HZ;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
836
837
838
839
  	return c;
  }
  
  /*
   *	A cache entry has gone into a resolved state from queued
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
840

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
841
842
  static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
  			       struct mfc_cache *uc, struct mfc_cache *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
  {
  	struct sk_buff *skb;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
845
  	struct nlmsgerr *e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

a8cb16dd9   Eric Dumazet   ipmr: cleanups
847
  	/* Play the pending entries through our router */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

c354e1246   Jianjun Kong   net: clean up net...
849
  	while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
850
  		if (ip_hdr(skb)->version == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
573ce260b   Hong zhi guo   net-next: replace...
852
  			if (__ipmr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
a8cb16dd9   Eric Dumazet   ipmr: cleanups
853
854
  				nlh->nlmsg_len = skb_tail_pointer(skb) -
  						 (u8 *)nlh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
  			} else {
  				nlh->nlmsg_type = NLMSG_ERROR;
573ce260b   Hong zhi guo   net-next: replace...
857
  				nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  				skb_trim(skb, nlh->nlmsg_len);
573ce260b   Hong zhi guo   net-next: replace...
859
  				e = nlmsg_data(nlh);
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
860
861
  				e->error = -EMSGSIZE;
  				memset(&e->msg, 0, sizeof(e->msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
  			}
2942e9005   Thomas Graf   [RTNETLINK]: Use ...
863

15e473046   Eric W. Biederman   netlink: Rename p...
864
  			rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
865
  		} else {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
866
  			ip_mr_forward(net, mrt, skb, c, 0);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
867
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
871
872
873
874
875
876
  	}
  }
  
  /*
   *	Bounce a cache query up to mrouted. We could use netlink for this but mrouted
   *	expects the following bizarre scheme.
   *
   *	Called under mrt_lock.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
877

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
878
  static int ipmr_cache_report(struct mr_table *mrt,
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
879
  			     struct sk_buff *pkt, vifi_t vifi, int assert)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
  {
  	struct sk_buff *skb;
c9bdd4b52   Arnaldo Carvalho de Melo   [IP]: Introduce i...
882
  	const int ihl = ip_hdrlen(pkt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  	struct igmphdr *igmp;
  	struct igmpmsg *msg;
4c9687098   Eric Dumazet   ipmr: RCU convers...
885
  	struct sock *mroute_sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
887
888
889
890
891
892
893
  	int ret;
  
  #ifdef CONFIG_IP_PIMSM
  	if (assert == IGMPMSG_WHOLEPKT)
  		skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
  	else
  #endif
  		skb = alloc_skb(128, GFP_ATOMIC);
132adf546   Stephen Hemminger   [IPV4]: cleanup
894
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
  		return -ENOBUFS;
  
  #ifdef CONFIG_IP_PIMSM
  	if (assert == IGMPMSG_WHOLEPKT) {
  		/* Ugly, but we have no choice with this interface.
a8cb16dd9   Eric Dumazet   ipmr: cleanups
900
901
902
  		 * Duplicate old header, fix ihl, length etc.
  		 * And all this only to mangle msg->im_msgtype and
  		 * to set msg->im_mbz to "mbz" :-)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  		 */
878c81450   Arnaldo Carvalho de Melo   [SK_BUFF] ipmr: A...
904
905
  		skb_push(skb, sizeof(struct iphdr));
  		skb_reset_network_header(skb);
badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
906
  		skb_reset_transport_header(skb);
0272ffc46   Arnaldo Carvalho de Melo   [SK_BUFF] ipmr: M...
907
  		msg = (struct igmpmsg *)skb_network_header(skb);
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
908
  		memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
  		msg->im_msgtype = IGMPMSG_WHOLEPKT;
  		msg->im_mbz = 0;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
911
  		msg->im_vif = mrt->mroute_reg_vif_num;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
912
913
914
  		ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
  		ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
  					     sizeof(struct iphdr));
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
915
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  #endif
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
917
  	{
a8cb16dd9   Eric Dumazet   ipmr: cleanups
918
  	/* Copy the IP header */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919

27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
920
  	skb->network_header = skb->tail;
ddc7b8e32   Arnaldo Carvalho de Melo   [SK_BUFF]: Some m...
921
  	skb_put(skb, ihl);
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
922
  	skb_copy_to_linear_data(skb, pkt->data, ihl);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
923
  	ip_hdr(skb)->protocol = 0;	/* Flag to the kernel this is a route add */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
924
  	msg = (struct igmpmsg *)skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  	msg->im_vif = vifi;
adf30907d   Eric Dumazet   net: skb->dst acc...
926
  	skb_dst_set(skb, dst_clone(skb_dst(pkt)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927

a8cb16dd9   Eric Dumazet   ipmr: cleanups
928
  	/* Add our header */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929

a8cb16dd9   Eric Dumazet   ipmr: cleanups
930
  	igmp = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
  	igmp->type	=
  	msg->im_msgtype = assert;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
933
934
  	igmp->code	= 0;
  	ip_hdr(skb)->tot_len = htons(skb->len);		/* Fix the length */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
935
  	skb->transport_header = skb->network_header;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
936
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937

4c9687098   Eric Dumazet   ipmr: RCU convers...
938
939
940
941
  	rcu_read_lock();
  	mroute_sk = rcu_dereference(mrt->mroute_sk);
  	if (mroute_sk == NULL) {
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
  		kfree_skb(skb);
  		return -EINVAL;
  	}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
945
  	/* Deliver to mrouted */
4c9687098   Eric Dumazet   ipmr: RCU convers...
946
947
  	ret = sock_queue_rcv_skb(mroute_sk, skb);
  	rcu_read_unlock();
70a269e6c   Benjamin Thery   netns: ipmr: allo...
948
  	if (ret < 0) {
e87cc4728   Joe Perches   net: Convert net_...
949
950
  		net_warn_ratelimited("mroute: pending queue full, dropping entries
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
957
958
959
  		kfree_skb(skb);
  	}
  
  	return ret;
  }
  
  /*
   *	Queue a packet for resolution. It gets locked cache entry!
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
960

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  static int
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
962
  ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
964
  	bool found = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
  	int err;
  	struct mfc_cache *c;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
967
  	const struct iphdr *iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
  
  	spin_lock_bh(&mfc_unres_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
970
  	list_for_each_entry(c, &mrt->mfc_unres_queue, list) {
e258beb22   Patrick McHardy   ipv4: ipmr: move ...
971
  		if (c->mfc_mcastgrp == iph->daddr &&
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
972
973
  		    c->mfc_origin == iph->saddr) {
  			found = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  			break;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
975
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
  	}
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
977
  	if (!found) {
a8cb16dd9   Eric Dumazet   ipmr: cleanups
978
  		/* Create a new entry if allowable */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
980
  		if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
d658f8a0e   Patrick McHardy   ipv4: ipmr: remov...
981
  		    (c = ipmr_cache_alloc_unres()) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
  			spin_unlock_bh(&mfc_unres_lock);
  
  			kfree_skb(skb);
  			return -ENOBUFS;
  		}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
987
  		/* Fill in the new cache entry */
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
988
989
990
  		c->mfc_parent	= -1;
  		c->mfc_origin	= iph->saddr;
  		c->mfc_mcastgrp	= iph->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991

a8cb16dd9   Eric Dumazet   ipmr: cleanups
992
  		/* Reflect first query at mrouted. */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
993
  		err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
994
  		if (err < 0) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
995
  			/* If the report failed throw the cache entry
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
  			   out - Brad Parker
  			 */
  			spin_unlock_bh(&mfc_unres_lock);
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
999
  			ipmr_cache_free(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
  			kfree_skb(skb);
  			return err;
  		}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1003
1004
  		atomic_inc(&mrt->cache_resolve_queue_len);
  		list_add(&c->list, &mrt->mfc_unres_queue);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1005
  		mroute_netlink_event(mrt, c, RTM_NEWROUTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006

278554bd6   David S. Miller   Merge branch 'mas...
1007
1008
  		if (atomic_read(&mrt->cache_resolve_queue_len) == 1)
  			mod_timer(&mrt->ipmr_expire_timer, c->mfc_un.unres.expires);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  	}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1010
1011
1012
  	/* See if we can append the packet */
  
  	if (c->mfc_un.unres.unresolved.qlen > 3) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
  		kfree_skb(skb);
  		err = -ENOBUFS;
  	} else {
c354e1246   Jianjun Kong   net: clean up net...
1016
  		skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
  		err = 0;
  	}
  
  	spin_unlock_bh(&mfc_unres_lock);
  	return err;
  }
  
  /*
   *	MFC cache manipulation by user space mroute daemon
   */
660b26dc1   Nicolas Dichtel   mcast: add multic...
1027
  static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
1029
  {
  	int line;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1030
  	struct mfc_cache *c, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031

c354e1246   Jianjun Kong   net: clean up net...
1032
  	line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1034
  	list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  		if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
1036
1037
  		    c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
  		    (parent == -1 || parent == c->mfc_parent)) {
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1038
  			list_del_rcu(&c->list);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1039
  			mroute_netlink_event(mrt, c, RTM_DELROUTE);
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
1040
  			ipmr_cache_free(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
  			return 0;
  		}
  	}
  	return -ENOENT;
  }
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1046
  static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
660b26dc1   Nicolas Dichtel   mcast: add multic...
1047
  			struct mfcctl *mfc, int mrtsock, int parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1049
  	bool found = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  	int line;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1051
  	struct mfc_cache *uc, *c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052

a50436f2c   Patrick McHardy   net: ipmr/ip6mr: ...
1053
1054
  	if (mfc->mfcc_parent >= MAXVIFS)
  		return -ENFILE;
c354e1246   Jianjun Kong   net: clean up net...
1055
  	line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1057
  	list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
  		if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
1059
1060
  		    c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
  		    (parent == -1 || parent == c->mfc_parent)) {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1061
  			found = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
  			break;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1063
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
  	}
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1065
  	if (found) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
  		write_lock_bh(&mrt_lock);
  		c->mfc_parent = mfc->mfcc_parent;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1068
  		ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
  		if (!mrtsock)
  			c->mfc_flags |= MFC_STATIC;
  		write_unlock_bh(&mrt_lock);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1072
  		mroute_netlink_event(mrt, c, RTM_NEWROUTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
  		return 0;
  	}
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
1075
  	if (mfc->mfcc_mcastgrp.s_addr != htonl(INADDR_ANY) &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
1076
  	    !ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  		return -EINVAL;
d658f8a0e   Patrick McHardy   ipv4: ipmr: remov...
1078
  	c = ipmr_cache_alloc();
c354e1246   Jianjun Kong   net: clean up net...
1079
  	if (c == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
  		return -ENOMEM;
c354e1246   Jianjun Kong   net: clean up net...
1081
1082
1083
  	c->mfc_origin = mfc->mfcc_origin.s_addr;
  	c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
  	c->mfc_parent = mfc->mfcc_parent;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1084
  	ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
  	if (!mrtsock)
  		c->mfc_flags |= MFC_STATIC;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1087
  	list_add_rcu(&c->list, &mrt->mfc_cache_array[line]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
1092
  
  	/*
  	 *	Check to see if we resolved a queued list. If so we
  	 *	need to send on the frames and tidy up.
  	 */
b0ebb739a   Patrick McHardy   ipv4: ipmr: fix i...
1093
  	found = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
  	spin_lock_bh(&mfc_unres_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1095
  	list_for_each_entry(uc, &mrt->mfc_unres_queue, list) {
e258beb22   Patrick McHardy   ipv4: ipmr: move ...
1096
  		if (uc->mfc_origin == c->mfc_origin &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
  		    uc->mfc_mcastgrp == c->mfc_mcastgrp) {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1098
  			list_del(&uc->list);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1099
  			atomic_dec(&mrt->cache_resolve_queue_len);
b0ebb739a   Patrick McHardy   ipv4: ipmr: fix i...
1100
  			found = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
  			break;
  		}
  	}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1104
1105
  	if (list_empty(&mrt->mfc_unres_queue))
  		del_timer(&mrt->ipmr_expire_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
  	spin_unlock_bh(&mfc_unres_lock);
b0ebb739a   Patrick McHardy   ipv4: ipmr: fix i...
1107
  	if (found) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1108
  		ipmr_cache_resolve(net, mrt, uc, c);
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
1109
  		ipmr_cache_free(uc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  	}
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1111
  	mroute_netlink_event(mrt, c, RTM_NEWROUTE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
1116
1117
  	return 0;
  }
  
  /*
   *	Close the multicast socket, and clear the vif tables etc
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1118

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1119
  static void mroute_clean_tables(struct mr_table *mrt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1120
1121
  {
  	int i;
d17fa6fa8   Eric Dumazet   ipmr: Optimize mu...
1122
  	LIST_HEAD(list);
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1123
  	struct mfc_cache *c, *next;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1124

a8cb16dd9   Eric Dumazet   ipmr: cleanups
1125
  	/* Shut down all active vif entries */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1126
  	for (i = 0; i < mrt->maxvif; i++) {
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1127
  		if (!(mrt->vif_table[i].flags & VIFF_STATIC))
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1128
  			vif_delete(mrt, i, 0, &list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  	}
d17fa6fa8   Eric Dumazet   ipmr: Optimize mu...
1130
  	unregister_netdevice_many(&list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131

a8cb16dd9   Eric Dumazet   ipmr: cleanups
1132
  	/* Wipe the cache */
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1133
  	for (i = 0; i < MFC_LINES; i++) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1134
  		list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1135
  			if (c->mfc_flags & MFC_STATIC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  				continue;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1137
  			list_del_rcu(&c->list);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1138
  			mroute_netlink_event(mrt, c, RTM_DELROUTE);
5c0a66f5f   Benjamin Thery   netns: ipmr: stor...
1139
  			ipmr_cache_free(c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
  		}
  	}
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1142
  	if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  		spin_lock_bh(&mfc_unres_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1144
  		list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
1145
  			list_del(&c->list);
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
1146
  			mroute_netlink_event(mrt, c, RTM_DELROUTE);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1147
  			ipmr_destroy_unres(mrt, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
  		}
  		spin_unlock_bh(&mfc_unres_lock);
  	}
  }
4c9687098   Eric Dumazet   ipmr: RCU convers...
1152
1153
1154
  /* called from ip_ra_control(), before an RCU grace period,
   * we dont need to call synchronize_rcu() here
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
  static void mrtsock_destruct(struct sock *sk)
  {
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1157
  	struct net *net = sock_net(sk);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1158
  	struct mr_table *mrt;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1159

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  	rtnl_lock();
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1161
  	ipmr_for_each_table(mrt, net) {
4c9687098   Eric Dumazet   ipmr: RCU convers...
1162
  		if (sk == rtnl_dereference(mrt->mroute_sk)) {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1163
  			IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
d67b8c616   Nicolas Dichtel   netconf: advertis...
1164
1165
1166
  			inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
  						    NETCONFA_IFINDEX_ALL,
  						    net->ipv4.devconf_all);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
1167
  			RCU_INIT_POINTER(mrt->mroute_sk, NULL);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1168
1169
  			mroute_clean_tables(mrt);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  	}
  	rtnl_unlock();
  }
  
  /*
   *	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.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1180

b7058842c   David S. Miller   net: Make setsock...
1181
  int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1183
  	int ret, parent = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
1185
  	struct vifctl vif;
  	struct mfcctl mfc;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1186
  	struct net *net = sock_net(sk);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1187
  	struct mr_table *mrt;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1188
1189
1190
  	if (sk->sk_type != SOCK_RAW ||
  	    inet_sk(sk)->inet_num != IPPROTO_IGMP)
  		return -EOPNOTSUPP;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1191
1192
1193
  	mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return -ENOENT;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1194

132adf546   Stephen Hemminger   [IPV4]: cleanup
1195
  	if (optname != MRT_INIT) {
33d480ce6   Eric Dumazet   net: cleanup some...
1196
  		if (sk != rcu_access_pointer(mrt->mroute_sk) &&
52e804c6d   Eric W. Biederman   net: Allow userns...
1197
  		    !ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
1199
  			return -EACCES;
  	}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1200
1201
  	switch (optname) {
  	case MRT_INIT:
c354e1246   Jianjun Kong   net: clean up net...
1202
  		if (optlen != sizeof(int))
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1203
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204

132adf546   Stephen Hemminger   [IPV4]: cleanup
1205
  		rtnl_lock();
4c9687098   Eric Dumazet   ipmr: RCU convers...
1206
  		if (rtnl_dereference(mrt->mroute_sk)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
  			rtnl_unlock();
132adf546   Stephen Hemminger   [IPV4]: cleanup
1208
1209
1210
1211
1212
  			return -EADDRINUSE;
  		}
  
  		ret = ip_ra_control(sk, 1, mrtsock_destruct);
  		if (ret == 0) {
cf778b00e   Eric Dumazet   net: reintroduce ...
1213
  			rcu_assign_pointer(mrt->mroute_sk, sk);
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1214
  			IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
d67b8c616   Nicolas Dichtel   netconf: advertis...
1215
1216
1217
  			inet_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
  						    NETCONFA_IFINDEX_ALL,
  						    net->ipv4.devconf_all);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1218
1219
1220
1221
  		}
  		rtnl_unlock();
  		return ret;
  	case MRT_DONE:
33d480ce6   Eric Dumazet   net: cleanup some...
1222
  		if (sk != rcu_access_pointer(mrt->mroute_sk))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1223
1224
1225
1226
  			return -EACCES;
  		return ip_ra_control(sk, 0, NULL);
  	case MRT_ADD_VIF:
  	case MRT_DEL_VIF:
c354e1246   Jianjun Kong   net: clean up net...
1227
  		if (optlen != sizeof(vif))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1228
  			return -EINVAL;
c354e1246   Jianjun Kong   net: clean up net...
1229
  		if (copy_from_user(&vif, optval, sizeof(vif)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1230
1231
1232
1233
  			return -EFAULT;
  		if (vif.vifc_vifi >= MAXVIFS)
  			return -ENFILE;
  		rtnl_lock();
c354e1246   Jianjun Kong   net: clean up net...
1234
  		if (optname == MRT_ADD_VIF) {
4c9687098   Eric Dumazet   ipmr: RCU convers...
1235
1236
  			ret = vif_add(net, mrt, &vif,
  				      sk == rtnl_dereference(mrt->mroute_sk));
132adf546   Stephen Hemminger   [IPV4]: cleanup
1237
  		} else {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1238
  			ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1239
1240
1241
  		}
  		rtnl_unlock();
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
1244
1245
1246
  
  		/*
  		 *	Manipulate the forwarding caches. These live
  		 *	in a sort of kernel/user symbiosis.
  		 */
132adf546   Stephen Hemminger   [IPV4]: cleanup
1247
1248
  	case MRT_ADD_MFC:
  	case MRT_DEL_MFC:
660b26dc1   Nicolas Dichtel   mcast: add multic...
1249
1250
1251
  		parent = -1;
  	case MRT_ADD_MFC_PROXY:
  	case MRT_DEL_MFC_PROXY:
c354e1246   Jianjun Kong   net: clean up net...
1252
  		if (optlen != sizeof(mfc))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1253
  			return -EINVAL;
c354e1246   Jianjun Kong   net: clean up net...
1254
  		if (copy_from_user(&mfc, optval, sizeof(mfc)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1255
  			return -EFAULT;
660b26dc1   Nicolas Dichtel   mcast: add multic...
1256
1257
  		if (parent == 0)
  			parent = mfc.mfcc_parent;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1258
  		rtnl_lock();
660b26dc1   Nicolas Dichtel   mcast: add multic...
1259
1260
  		if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY)
  			ret = ipmr_mfc_delete(mrt, &mfc, parent);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1261
  		else
4c9687098   Eric Dumazet   ipmr: RCU convers...
1262
  			ret = ipmr_mfc_add(net, mrt, &mfc,
660b26dc1   Nicolas Dichtel   mcast: add multic...
1263
1264
  					   sk == rtnl_dereference(mrt->mroute_sk),
  					   parent);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1265
1266
  		rtnl_unlock();
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
  		/*
  		 *	Control PIM assert.
  		 */
132adf546   Stephen Hemminger   [IPV4]: cleanup
1270
1271
1272
  	case MRT_ASSERT:
  	{
  		int v;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1273
1274
  		if (optlen != sizeof(v))
  			return -EINVAL;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1275
  		if (get_user(v, (int __user *)optval))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1276
  			return -EFAULT;
53d6841d2   Joe Perches   ipv4/ipmr and ipv...
1277
  		mrt->mroute_do_assert = v;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1278
1279
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  #ifdef CONFIG_IP_PIMSM
132adf546   Stephen Hemminger   [IPV4]: cleanup
1281
1282
  	case MRT_PIM:
  	{
ba93ef746   Stephen Hemminger   [IPV4]: ipmr spar...
1283
  		int v;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1284
1285
  		if (optlen != sizeof(v))
  			return -EINVAL;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1286
  		if (get_user(v, (int __user *)optval))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1287
  			return -EFAULT;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1288
  		v = !!v;
ba93ef746   Stephen Hemminger   [IPV4]: ipmr spar...
1289

132adf546   Stephen Hemminger   [IPV4]: cleanup
1290
1291
  		rtnl_lock();
  		ret = 0;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1292
1293
1294
  		if (v != mrt->mroute_do_pim) {
  			mrt->mroute_do_pim = v;
  			mrt->mroute_do_assert = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1296
1297
1298
  		rtnl_unlock();
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
  #endif
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1300
1301
1302
1303
1304
1305
1306
1307
1308
  #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
  	case MRT_TABLE:
  	{
  		u32 v;
  
  		if (optlen != sizeof(u32))
  			return -EINVAL;
  		if (get_user(v, (u32 __user *)optval))
  			return -EFAULT;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1309

b49d3c1e1   Eric Dumazet   net: ipmr: limit ...
1310
1311
1312
  		/* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */
  		if (v != RT_TABLE_DEFAULT && v >= 1000000000)
  			return -EINVAL;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1313
1314
  		rtnl_lock();
  		ret = 0;
4c9687098   Eric Dumazet   ipmr: RCU convers...
1315
1316
1317
1318
1319
  		if (sk == rtnl_dereference(mrt->mroute_sk)) {
  			ret = -EBUSY;
  		} else {
  			if (!ipmr_new_table(net, v))
  				ret = -ENOMEM;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1320
1321
  			else
  				raw_sk(sk)->ipmr_table = v;
4c9687098   Eric Dumazet   ipmr: RCU convers...
1322
  		}
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1323
1324
1325
1326
  		rtnl_unlock();
  		return ret;
  	}
  #endif
132adf546   Stephen Hemminger   [IPV4]: cleanup
1327
1328
1329
1330
1331
1332
  	/*
  	 *	Spurious command, or MRT_VERSION which you cannot
  	 *	set.
  	 */
  	default:
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
1336
1337
1338
  	}
  }
  
  /*
   *	Getsock opt support for the multicast routing system.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1339

c354e1246   Jianjun Kong   net: clean up net...
1340
  int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
1343
  {
  	int olr;
  	int val;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1344
  	struct net *net = sock_net(sk);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1345
  	struct mr_table *mrt;
5e1859fbc   Eric Dumazet   ipv4: ipmr: vario...
1346
1347
1348
  	if (sk->sk_type != SOCK_RAW ||
  	    inet_sk(sk)->inet_num != IPPROTO_IGMP)
  		return -EOPNOTSUPP;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1349
1350
1351
  	mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352

c354e1246   Jianjun Kong   net: clean up net...
1353
  	if (optname != MRT_VERSION &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
  #ifdef CONFIG_IP_PIMSM
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1355
  	   optname != MRT_PIM &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
  #endif
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1357
  	   optname != MRT_ASSERT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
1362
1363
1364
1365
  		return -ENOPROTOOPT;
  
  	if (get_user(olr, optlen))
  		return -EFAULT;
  
  	olr = min_t(unsigned int, olr, sizeof(int));
  	if (olr < 0)
  		return -EINVAL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1366

c354e1246   Jianjun Kong   net: clean up net...
1367
  	if (put_user(olr, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
  		return -EFAULT;
c354e1246   Jianjun Kong   net: clean up net...
1369
1370
  	if (optname == MRT_VERSION)
  		val = 0x0305;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
  #ifdef CONFIG_IP_PIMSM
c354e1246   Jianjun Kong   net: clean up net...
1372
  	else if (optname == MRT_PIM)
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1373
  		val = mrt->mroute_do_pim;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
  #endif
  	else
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1376
  		val = mrt->mroute_do_assert;
c354e1246   Jianjun Kong   net: clean up net...
1377
  	if (copy_to_user(optval, &val, olr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
1379
1380
1381
1382
1383
1384
  		return -EFAULT;
  	return 0;
  }
  
  /*
   *	The IP multicast ioctl support routines.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1385

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
1387
1388
1389
1390
1391
  int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
  {
  	struct sioc_sg_req sr;
  	struct sioc_vif_req vr;
  	struct vif_device *vif;
  	struct mfc_cache *c;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1392
  	struct net *net = sock_net(sk);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1393
1394
1395
1396
1397
  	struct mr_table *mrt;
  
  	mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return -ENOENT;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1398

132adf546   Stephen Hemminger   [IPV4]: cleanup
1399
1400
  	switch (cmd) {
  	case SIOCGETVIFCNT:
c354e1246   Jianjun Kong   net: clean up net...
1401
  		if (copy_from_user(&vr, arg, sizeof(vr)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1402
  			return -EFAULT;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1403
  		if (vr.vifi >= mrt->maxvif)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1404
1405
  			return -EINVAL;
  		read_lock(&mrt_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1406
1407
  		vif = &mrt->vif_table[vr.vifi];
  		if (VIF_EXISTS(mrt, vr.vifi)) {
c354e1246   Jianjun Kong   net: clean up net...
1408
1409
1410
1411
  			vr.icount = vif->pkt_in;
  			vr.ocount = vif->pkt_out;
  			vr.ibytes = vif->bytes_in;
  			vr.obytes = vif->bytes_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
  			read_unlock(&mrt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413

c354e1246   Jianjun Kong   net: clean up net...
1414
  			if (copy_to_user(arg, &vr, sizeof(vr)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1415
1416
1417
1418
1419
1420
  				return -EFAULT;
  			return 0;
  		}
  		read_unlock(&mrt_lock);
  		return -EADDRNOTAVAIL;
  	case SIOCGETSGCNT:
c354e1246   Jianjun Kong   net: clean up net...
1421
  		if (copy_from_user(&sr, arg, sizeof(sr)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1422
  			return -EFAULT;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1423
  		rcu_read_lock();
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1424
  		c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1425
1426
1427
1428
  		if (c) {
  			sr.pktcnt = c->mfc_un.res.pkt;
  			sr.bytecnt = c->mfc_un.res.bytes;
  			sr.wrong_if = c->mfc_un.res.wrong_if;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1429
  			rcu_read_unlock();
132adf546   Stephen Hemminger   [IPV4]: cleanup
1430

c354e1246   Jianjun Kong   net: clean up net...
1431
  			if (copy_to_user(arg, &sr, sizeof(sr)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1432
1433
1434
  				return -EFAULT;
  			return 0;
  		}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1435
  		rcu_read_unlock();
132adf546   Stephen Hemminger   [IPV4]: cleanup
1436
1437
1438
  		return -EADDRNOTAVAIL;
  	default:
  		return -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
  	}
  }
709b46e8d   Eric W. Biederman   net: Add compat i...
1441
1442
1443
1444
1445
1446
1447
1448
  #ifdef CONFIG_COMPAT
  struct compat_sioc_sg_req {
  	struct in_addr src;
  	struct in_addr grp;
  	compat_ulong_t pktcnt;
  	compat_ulong_t bytecnt;
  	compat_ulong_t wrong_if;
  };
ca6b8bb09   David S. Miller   net: Support comp...
1449
1450
1451
1452
1453
1454
1455
  struct compat_sioc_vif_req {
  	vifi_t	vifi;		/* Which iface */
  	compat_ulong_t icount;
  	compat_ulong_t ocount;
  	compat_ulong_t ibytes;
  	compat_ulong_t obytes;
  };
709b46e8d   Eric W. Biederman   net: Add compat i...
1456
1457
  int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
  {
0033d5ad2   David S. Miller   net: Fix bug in c...
1458
  	struct compat_sioc_sg_req sr;
ca6b8bb09   David S. Miller   net: Support comp...
1459
1460
  	struct compat_sioc_vif_req vr;
  	struct vif_device *vif;
709b46e8d   Eric W. Biederman   net: Add compat i...
1461
1462
1463
1464
1465
1466
1467
1468
1469
  	struct mfc_cache *c;
  	struct net *net = sock_net(sk);
  	struct mr_table *mrt;
  
  	mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return -ENOENT;
  
  	switch (cmd) {
ca6b8bb09   David S. Miller   net: Support comp...
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
  	case SIOCGETVIFCNT:
  		if (copy_from_user(&vr, arg, sizeof(vr)))
  			return -EFAULT;
  		if (vr.vifi >= mrt->maxvif)
  			return -EINVAL;
  		read_lock(&mrt_lock);
  		vif = &mrt->vif_table[vr.vifi];
  		if (VIF_EXISTS(mrt, vr.vifi)) {
  			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;
709b46e8d   Eric W. Biederman   net: Add compat i...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
  	case SIOCGETSGCNT:
  		if (copy_from_user(&sr, arg, sizeof(sr)))
  			return -EFAULT;
  
  		rcu_read_lock();
  		c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
  		if (c) {
  			sr.pktcnt = c->mfc_un.res.pkt;
  			sr.bytecnt = c->mfc_un.res.bytes;
  			sr.wrong_if = c->mfc_un.res.wrong_if;
  			rcu_read_unlock();
  
  			if (copy_to_user(arg, &sr, sizeof(sr)))
  				return -EFAULT;
  			return 0;
  		}
  		rcu_read_unlock();
  		return -EADDRNOTAVAIL;
  	default:
  		return -ENOIOCTLCMD;
  	}
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1513
1514
1515
  
  static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
e9dc86534   Eric W. Biederman   [NET]: Make devic...
1516
  	struct net_device *dev = ptr;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1517
  	struct net *net = dev_net(dev);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1518
  	struct mr_table *mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
1520
  	struct vif_device *v;
  	int ct;
e9dc86534   Eric W. Biederman   [NET]: Make devic...
1521

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
  	if (event != NETDEV_UNREGISTER)
  		return NOTIFY_DONE;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1524
1525
1526
1527
1528
  
  	ipmr_for_each_table(mrt, net) {
  		v = &mrt->vif_table[0];
  		for (ct = 0; ct < mrt->maxvif; ct++, v++) {
  			if (v->dev == dev)
e92036a65   RongQing.Li   ipv4: remove usel...
1529
  				vif_delete(mrt, ct, 1, NULL);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1530
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
1532
1533
  	}
  	return NOTIFY_DONE;
  }
c354e1246   Jianjun Kong   net: clean up net...
1534
  static struct notifier_block ip_mr_notifier = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
1537
1538
  	.notifier_call = ipmr_device_event,
  };
  
  /*
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1539
   *	Encapsulate a packet by attaching a valid IPIP header to it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
1541
1542
   *	This avoids tunnel drivers and other mess and gives us the speed so
   *	important for multicast video.
   */
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1543

114c7844f   Al Viro   [IPV4]: mroute an...
1544
  static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
  {
8856dfa3e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1546
  	struct iphdr *iph;
b71d1d426   Eric Dumazet   inet: constify ip...
1547
  	const struct iphdr *old_iph = ip_hdr(skb);
8856dfa3e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1548
1549
  
  	skb_push(skb, sizeof(struct iphdr));
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1550
  	skb->transport_header = skb->network_header;
8856dfa3e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
1551
  	skb_reset_network_header(skb);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1552
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553

a8cb16dd9   Eric Dumazet   ipmr: cleanups
1554
  	iph->version	=	4;
e023dd643   Arnaldo Carvalho de Melo   [IPMR]: Fix bug i...
1555
1556
  	iph->tos	=	old_iph->tos;
  	iph->ttl	=	old_iph->ttl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
1558
1559
1560
1561
1562
  	iph->frag_off	=	0;
  	iph->daddr	=	daddr;
  	iph->saddr	=	saddr;
  	iph->protocol	=	IPPROTO_IPIP;
  	iph->ihl	=	5;
  	iph->tot_len	=	htons(skb->len);
68a9e7078   Ansis Atteka   ip: generate uniq...
1563
  	ip_select_ident(skb, skb_dst(skb), NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  	ip_send_check(iph);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
1570
  	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
  	nf_reset(skb);
  }
  
  static inline int ipmr_forward_finish(struct sk_buff *skb)
  {
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1571
  	struct ip_options *opt = &(IPCB(skb)->opt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572

adf30907d   Eric Dumazet   net: skb->dst acc...
1573
  	IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
2d8dbb04c   Vincent Bernat   snmp: fix OutOcte...
1574
  	IP_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTOCTETS, skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
  
  	if (unlikely(opt->optlen))
  		ip_forward_options(skb);
  
  	return dst_output(skb);
  }
  
  /*
   *	Processing handlers for ipmr_forward
   */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1585
1586
  static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
  			    struct sk_buff *skb, struct mfc_cache *c, int vifi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
  {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1588
  	const struct iphdr *iph = ip_hdr(skb);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1589
  	struct vif_device *vif = &mrt->vif_table[vifi];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590
1591
  	struct net_device *dev;
  	struct rtable *rt;
31e4543db   David S. Miller   ipv4: Make caller...
1592
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1593
1594
1595
1596
1597
1598
1599
1600
  	int    encap = 0;
  
  	if (vif->dev == NULL)
  		goto out_free;
  
  #ifdef CONFIG_IP_PIMSM
  	if (vif->flags & VIFF_REGISTER) {
  		vif->pkt_out++;
c354e1246   Jianjun Kong   net: clean up net...
1601
  		vif->bytes_out += skb->len;
cf3677ae1   Pavel Emelyanov   ipmr: Use on-devi...
1602
1603
  		vif->dev->stats.tx_bytes += skb->len;
  		vif->dev->stats.tx_packets++;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1604
  		ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
69ebbf58f   Ilpo Järvinen   ipmr: use goto to...
1605
  		goto out_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
  	}
  #endif
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1608
  	if (vif->flags & VIFF_TUNNEL) {
31e4543db   David S. Miller   ipv4: Make caller...
1609
  		rt = ip_route_output_ports(net, &fl4, NULL,
78fbfd8a6   David S. Miller   ipv4: Create and ...
1610
1611
1612
1613
  					   vif->remote, vif->local,
  					   0, 0,
  					   IPPROTO_IPIP,
  					   RT_TOS(iph->tos), vif->link);
b23dd4fe4   David S. Miller   ipv4: Make output...
1614
  		if (IS_ERR(rt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
1617
  			goto out_free;
  		encap = sizeof(struct iphdr);
  	} else {
31e4543db   David S. Miller   ipv4: Make caller...
1618
  		rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0,
78fbfd8a6   David S. Miller   ipv4: Create and ...
1619
1620
1621
  					   0, 0,
  					   IPPROTO_IPIP,
  					   RT_TOS(iph->tos), vif->link);
b23dd4fe4   David S. Miller   ipv4: Make output...
1622
  		if (IS_ERR(rt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
1624
  			goto out_free;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1625
  	dev = rt->dst.dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626

d8d1f30b9   Changli Gao   net-next: remove ...
1627
  	if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
  		/* Do not fragment multicasts. Alas, IPv4 does not
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1629
1630
  		 * allow to send ICMP, so that packets will disappear
  		 * to blackhole.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
  		 */
7c73a6faf   Pavel Emelyanov   mib: add net to I...
1632
  		IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
1634
1635
  		ip_rt_put(rt);
  		goto out_free;
  	}
d8d1f30b9   Changli Gao   net-next: remove ...
1636
  	encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
  
  	if (skb_cow(skb, encap)) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1639
  		ip_rt_put(rt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
1641
1642
1643
  		goto out_free;
  	}
  
  	vif->pkt_out++;
c354e1246   Jianjun Kong   net: clean up net...
1644
  	vif->bytes_out += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645

adf30907d   Eric Dumazet   net: skb->dst acc...
1646
  	skb_dst_drop(skb);
d8d1f30b9   Changli Gao   net-next: remove ...
1647
  	skb_dst_set(skb, &rt->dst);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1648
  	ip_decrease_ttl(ip_hdr(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
1650
  
  	/* FIXME: forward and output firewalls used to be called here.
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1651
1652
  	 * What do we do with netfilter? -- RR
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
1654
1655
  	if (vif->flags & VIFF_TUNNEL) {
  		ip_encap(skb, vif->local, vif->remote);
  		/* FIXME: extra output firewall step used to be here. --RR */
2f4c02d40   Pavel Emelyanov   ipmr: Ipip tunnel...
1656
1657
  		vif->dev->stats.tx_packets++;
  		vif->dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
  	}
  
  	IPCB(skb)->flags |= IPSKB_FORWARDED;
  
  	/*
  	 * 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.
  	 */
9bbc768aa   Jan Engelhardt   netfilter: ipv4: ...
1673
  	NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, dev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1674
1675
1676
1677
1678
  		ipmr_forward_finish);
  	return;
  
  out_free:
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
  }
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1680
  static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681
1682
  {
  	int ct;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1683
1684
1685
  
  	for (ct = mrt->maxvif-1; ct >= 0; ct--) {
  		if (mrt->vif_table[ct].dev == dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
1687
1688
1689
1690
1691
  			break;
  	}
  	return ct;
  }
  
  /* "local" means that we should preserve one skb (for local delivery) */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1692
1693
1694
  static int ip_mr_forward(struct net *net, struct mr_table *mrt,
  			 struct sk_buff *skb, struct mfc_cache *cache,
  			 int local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
1697
  {
  	int psend = -1;
  	int vif, ct;
660b26dc1   Nicolas Dichtel   mcast: add multic...
1698
  	int true_vifi = ipmr_find_vif(mrt, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
1701
1702
  
  	vif = cache->mfc_parent;
  	cache->mfc_un.res.pkt++;
  	cache->mfc_un.res.bytes += skb->len;
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
1703
  	if (cache->mfc_origin == htonl(INADDR_ANY) && true_vifi >= 0) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
  		struct mfc_cache *cache_proxy;
  
  		/* For an (*,G) entry, we only check that the incomming
  		 * interface is part of the static tree.
  		 */
  		cache_proxy = ipmr_cache_find_any_parent(mrt, vif);
  		if (cache_proxy &&
  		    cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
  			goto forward;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
1715
1716
  	/*
  	 * Wrong interface: drop packet and (maybe) send PIM assert.
  	 */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1717
  	if (mrt->vif_table[vif].dev != skb->dev) {
c75379676   David S. Miller   ipv4: Make rt->fl...
1718
  		if (rt_is_output_route(skb_rtable(skb))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
  			/* It is our own packet, looped back.
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1720
1721
1722
1723
1724
1725
1726
1727
1728
  			 * Very complicated situation...
  			 *
  			 * The best workaround until routing daemons will be
  			 * fixed is not to redistribute packet, if it was
  			 * send through wrong interface. It means, that
  			 * multicast applications WILL NOT work for
  			 * (S,G), which have default multicast route pointing
  			 * to wrong oif. In any case, it is not a good
  			 * idea to use multicasting applications on router.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
1731
1732
1733
  			 */
  			goto dont_forward;
  		}
  
  		cache->mfc_un.res.wrong_if++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1734

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1735
  		if (true_vifi >= 0 && mrt->mroute_do_assert &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
  		    /* pimsm uses asserts, when switching from RPT to SPT,
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1737
1738
1739
  		     * 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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1740
  		     */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1741
  		    (mrt->mroute_do_pim ||
6f9374a93   Benjamin Thery   netns: ipmr: decl...
1742
  		     cache->mfc_un.res.ttls[true_vifi] < 255) &&
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1743
  		    time_after(jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
1745
  			       cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
  			cache->mfc_un.res.last_assert = jiffies;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1746
  			ipmr_cache_report(mrt, skb, true_vifi, IGMPMSG_WRONGVIF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747
1748
1749
  		}
  		goto dont_forward;
  	}
660b26dc1   Nicolas Dichtel   mcast: add multic...
1750
  forward:
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1751
1752
  	mrt->vif_table[vif].pkt_in++;
  	mrt->vif_table[vif].bytes_in += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
  
  	/*
  	 *	Forward the frame
  	 */
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
1757
1758
  	if (cache->mfc_origin == htonl(INADDR_ANY) &&
  	    cache->mfc_mcastgrp == htonl(INADDR_ANY)) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
  		if (true_vifi >= 0 &&
  		    true_vifi != cache->mfc_parent &&
  		    ip_hdr(skb)->ttl >
  				cache->mfc_un.res.ttls[cache->mfc_parent]) {
  			/* It's an (*,*) entry and the packet is not coming from
  			 * the upstream: forward the packet to the upstream
  			 * only.
  			 */
  			psend = cache->mfc_parent;
  			goto last_forward;
  		}
  		goto dont_forward;
  	}
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1772
1773
  	for (ct = cache->mfc_un.res.maxvif - 1;
  	     ct >= cache->mfc_un.res.minvif; ct--) {
660b26dc1   Nicolas Dichtel   mcast: add multic...
1774
  		/* For (*,G) entry, don't forward to the incoming interface */
360eb5da6   Nicolas Dichtel   ipmr: fix sparse ...
1775
1776
  		if ((cache->mfc_origin != htonl(INADDR_ANY) ||
  		     ct != true_vifi) &&
660b26dc1   Nicolas Dichtel   mcast: add multic...
1777
  		    ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
1779
  			if (psend != -1) {
  				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1780

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
  				if (skb2)
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1782
1783
  					ipmr_queue_xmit(net, mrt, skb2, cache,
  							psend);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
  			}
c354e1246   Jianjun Kong   net: clean up net...
1785
  			psend = ct;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786
1787
  		}
  	}
660b26dc1   Nicolas Dichtel   mcast: add multic...
1788
  last_forward:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
1790
1791
  	if (psend != -1) {
  		if (local) {
  			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1792

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1793
  			if (skb2)
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1794
  				ipmr_queue_xmit(net, mrt, skb2, cache, psend);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1795
  		} else {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1796
  			ipmr_queue_xmit(net, mrt, skb, cache, psend);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797
1798
1799
1800
1801
1802
1803
1804
1805
  			return 0;
  		}
  	}
  
  dont_forward:
  	if (!local)
  		kfree_skb(skb);
  	return 0;
  }
417da66fa   David S. Miller   ipv4: Rework ipmr...
1806
  static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
1807
  {
417da66fa   David S. Miller   ipv4: Rework ipmr...
1808
1809
  	struct rtable *rt = skb_rtable(skb);
  	struct iphdr *iph = ip_hdr(skb);
da91981be   David S. Miller   ipv4: Use flowi4 ...
1810
  	struct flowi4 fl4 = {
417da66fa   David S. Miller   ipv4: Rework ipmr...
1811
1812
  		.daddr = iph->daddr,
  		.saddr = iph->saddr,
b0fe4a318   Julian Anastasov   ipv4: use RT_TOS ...
1813
  		.flowi4_tos = RT_TOS(iph->tos),
4fd551d7b   David S. Miller   ipv4: Kill rt->rt...
1814
1815
1816
  		.flowi4_oif = (rt_is_output_route(rt) ?
  			       skb->dev->ifindex : 0),
  		.flowi4_iif = (rt_is_output_route(rt) ?
1fb9489bf   Pavel Emelyanov   net: Loopback ifi...
1817
  			       LOOPBACK_IFINDEX :
4fd551d7b   David S. Miller   ipv4: Kill rt->rt...
1818
  			       skb->dev->ifindex),
b48698895   David Miller   ipv4: Remove 'rt_...
1819
  		.flowi4_mark = skb->mark,
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
1820
1821
1822
  	};
  	struct mr_table *mrt;
  	int err;
da91981be   David S. Miller   ipv4: Use flowi4 ...
1823
  	err = ipmr_fib_lookup(net, &fl4, &mrt);
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
1824
1825
1826
1827
  	if (err)
  		return ERR_PTR(err);
  	return mrt;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
1829
1830
  
  /*
   *	Multicast packets for forwarding arrive here
4c9687098   Eric Dumazet   ipmr: RCU convers...
1831
   *	Called with rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
1834
1835
1836
   */
  
  int ip_mr_input(struct sk_buff *skb)
  {
  	struct mfc_cache *cache;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1837
  	struct net *net = dev_net(skb->dev);
511c3f92a   Eric Dumazet   net: skb->rtable ...
1838
  	int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1839
  	struct mr_table *mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
  
  	/* Packet is looped back after forward, it should not be
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1842
  	 * forwarded second time, but still can be delivered locally.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
  	 */
4c9687098   Eric Dumazet   ipmr: RCU convers...
1844
  	if (IPCB(skb)->flags & IPSKB_FORWARDED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1845
  		goto dont_forward;
417da66fa   David S. Miller   ipv4: Rework ipmr...
1846
  	mrt = ipmr_rt_fib_lookup(net, skb);
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
1847
1848
1849
  	if (IS_ERR(mrt)) {
  		kfree_skb(skb);
  		return PTR_ERR(mrt);
e40dbc51f   Ben Greear   ipmr: Don't leak ...
1850
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1851
  	if (!local) {
4c9687098   Eric Dumazet   ipmr: RCU convers...
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
  		if (IPCB(skb)->opt.router_alert) {
  			if (ip_call_ra_chain(skb))
  				return 0;
  		} else if (ip_hdr(skb)->protocol == IPPROTO_IGMP) {
  			/* IGMPv1 (and broken IGMPv2 implementations sort of
  			 * Cisco IOS <= 11.2(8)) do not put router alert
  			 * option to IGMP packets destined to routable
  			 * groups. It is very bad, because it means
  			 * that we can forward NO IGMP messages.
  			 */
  			struct sock *mroute_sk;
  
  			mroute_sk = rcu_dereference(mrt->mroute_sk);
  			if (mroute_sk) {
  				nf_reset(skb);
  				raw_rcv(mroute_sk, skb);
  				return 0;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1870
1871
  		    }
  	}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1872
  	/* already under rcu_read_lock() */
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1873
  	cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
660b26dc1   Nicolas Dichtel   mcast: add multic...
1874
1875
1876
1877
1878
1879
1880
  	if (cache == NULL) {
  		int vif = ipmr_find_vif(mrt, skb->dev);
  
  		if (vif >= 0)
  			cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
  						    vif);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
1882
1883
1884
  
  	/*
  	 *	No usable cache entry
  	 */
c354e1246   Jianjun Kong   net: clean up net...
1885
  	if (cache == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
1887
1888
1889
1890
  		int vif;
  
  		if (local) {
  			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
  			ip_local_deliver(skb);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1891
  			if (skb2 == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
  				return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1893
1894
  			skb = skb2;
  		}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1895
  		read_lock(&mrt_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1896
  		vif = ipmr_find_vif(mrt, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1897
  		if (vif >= 0) {
0eae88f31   Eric Dumazet   net: Fix various ...
1898
  			int err2 = ipmr_cache_unresolved(mrt, vif, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
  			read_unlock(&mrt_lock);
0eae88f31   Eric Dumazet   net: Fix various ...
1900
  			return err2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
1902
1903
1904
1905
  		}
  		read_unlock(&mrt_lock);
  		kfree_skb(skb);
  		return -ENODEV;
  	}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
1906
  	read_lock(&mrt_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1907
  	ip_mr_forward(net, mrt, skb, cache, local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
  	read_unlock(&mrt_lock);
  
  	if (local)
  		return ip_local_deliver(skb);
  
  	return 0;
  
  dont_forward:
  	if (local)
  		return ip_local_deliver(skb);
  	kfree_skb(skb);
  	return 0;
  }
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1921
  #ifdef CONFIG_IP_PIMSM
55747a0a7   Eric Dumazet   ipmr: __pim_rcv()...
1922
  /* called with rcu_read_lock() */
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1923
1924
  static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
  		     unsigned int pimlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1925
  {
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1926
1927
  	struct net_device *reg_dev = NULL;
  	struct iphdr *encap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928

b1879204d   Ilpo Järvinen   ipmr: merge commo...
1929
  	encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
  	/*
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1931
1932
1933
1934
  	 * Check that:
  	 * a. packet is really sent to a multicast group
  	 * b. packet is not a NULL-REGISTER
  	 * c. packet is not truncated
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935
  	 */
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
1936
  	if (!ipv4_is_multicast(encap->daddr) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
  	    encap->tot_len == 0 ||
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1938
1939
  	    ntohs(encap->tot_len) + pimlen > skb->len)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1940
1941
  
  	read_lock(&mrt_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1942
1943
  	if (mrt->mroute_reg_vif_num >= 0)
  		reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
  	read_unlock(&mrt_lock);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1945
  	if (reg_dev == NULL)
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1946
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947

b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
1948
  	skb->mac_header = skb->network_header;
55747a0a7   Eric Dumazet   ipmr: __pim_rcv()...
1949
  	skb_pull(skb, (u8 *)encap - skb->data);
31c7711b5   Arnaldo Carvalho de Melo   [SK_BUFF]: Some m...
1950
  	skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1951
  	skb->protocol = htons(ETH_P_IP);
55747a0a7   Eric Dumazet   ipmr: __pim_rcv()...
1952
  	skb->ip_summed = CHECKSUM_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1953
  	skb->pkt_type = PACKET_HOST;
d19d56ddc   Eric Dumazet   net: Introduce sk...
1954
1955
  
  	skb_tunnel_rx(skb, reg_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956
  	netif_rx(skb);
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1957

55747a0a7   Eric Dumazet   ipmr: __pim_rcv()...
1958
  	return NET_RX_SUCCESS;
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1959
1960
1961
1962
1963
1964
1965
  }
  #endif
  
  #ifdef CONFIG_IP_PIMSM_V1
  /*
   * Handle IGMP messages of PIMv1
   */
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1966
  int pim_rcv_v1(struct sk_buff *skb)
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1967
1968
  {
  	struct igmphdr *pim;
4feb88e5c   Benjamin Thery   netns: ipmr: enab...
1969
  	struct net *net = dev_net(skb->dev);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1970
  	struct mr_table *mrt;
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1971
1972
1973
1974
1975
  
  	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
  		goto drop;
  
  	pim = igmp_hdr(skb);
417da66fa   David S. Miller   ipv4: Rework ipmr...
1976
  	mrt = ipmr_rt_fib_lookup(net, skb);
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
1977
1978
  	if (IS_ERR(mrt))
  		goto drop;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
1979
  	if (!mrt->mroute_do_pim ||
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1980
1981
  	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
  		goto drop;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1982
  	if (__pim_rcv(mrt, skb, sizeof(*pim))) {
b1879204d   Ilpo Järvinen   ipmr: merge commo...
1983
1984
1985
  drop:
  		kfree_skb(skb);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
1987
1988
1989
1990
  	return 0;
  }
  #endif
  
  #ifdef CONFIG_IP_PIMSM_V2
a8cb16dd9   Eric Dumazet   ipmr: cleanups
1991
  static int pim_rcv(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
  {
  	struct pimreghdr *pim;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
1994
1995
  	struct net *net = dev_net(skb->dev);
  	struct mr_table *mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996

b1879204d   Ilpo Järvinen   ipmr: merge commo...
1997
  	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1998
  		goto drop;
9c70220b7   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1999
  	pim = (struct pimreghdr *)skb_transport_header(skb);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
2000
2001
  	if (pim->type != ((PIM_VERSION << 4) | (PIM_REGISTER)) ||
  	    (pim->flags & PIM_NULL_REGISTER) ||
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2002
  	    (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
d3bc23e7e   Al Viro   [NET]: Annotate c...
2003
  	     csum_fold(skb_checksum(skb, 0, skb->len, 0))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
  		goto drop;
417da66fa   David S. Miller   ipv4: Rework ipmr...
2005
  	mrt = ipmr_rt_fib_lookup(net, skb);
ee3f1aaf9   David S. Miller   ipv4: Lookup mult...
2006
2007
  	if (IS_ERR(mrt))
  		goto drop;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2008
  	if (__pim_rcv(mrt, skb, sizeof(*pim))) {
b1879204d   Ilpo Järvinen   ipmr: merge commo...
2009
2010
2011
  drop:
  		kfree_skb(skb);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2012
2013
2014
  	return 0;
  }
  #endif
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2015
2016
  static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
  			      struct mfc_cache *c, struct rtmsg *rtm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017
2018
2019
  {
  	int ct;
  	struct rtnexthop *nhp;
92a395e52   Thomas Graf   ipmr: Do not use ...
2020
  	struct nlattr *mp_attr;
adfa85e45   Nicolas Dichtel   ipmr/ip6mr: adver...
2021
  	struct rta_mfc_stats mfcs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2022

7438189ba   Nicolas Dichtel   net: ipmr/ip6mr: ...
2023
  	/* If cache is unresolved, don't try to parse IIF and OIF */
ed0f160ad   Dan Carpenter   ipmr: off by one ...
2024
  	if (c->mfc_parent >= MAXVIFS)
7438189ba   Nicolas Dichtel   net: ipmr/ip6mr: ...
2025
  		return -ENOENT;
92a395e52   Thomas Graf   ipmr: Do not use ...
2026
2027
2028
  	if (VIF_EXISTS(mrt, c->mfc_parent) &&
  	    nla_put_u32(skb, RTA_IIF, mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029

92a395e52   Thomas Graf   ipmr: Do not use ...
2030
2031
  	if (!(mp_attr = nla_nest_start(skb, RTA_MULTIPATH)))
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2032
2033
  
  	for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2034
  		if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
92a395e52   Thomas Graf   ipmr: Do not use ...
2035
2036
2037
2038
  			if (!(nhp = nla_reserve_nohdr(skb, sizeof(*nhp)))) {
  				nla_nest_cancel(skb, mp_attr);
  				return -EMSGSIZE;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2039
2040
  			nhp->rtnh_flags = 0;
  			nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2041
  			nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042
2043
2044
  			nhp->rtnh_len = sizeof(*nhp);
  		}
  	}
92a395e52   Thomas Graf   ipmr: Do not use ...
2045
2046
  
  	nla_nest_end(skb, mp_attr);
adfa85e45   Nicolas Dichtel   ipmr/ip6mr: adver...
2047
2048
2049
2050
2051
  	mfcs.mfcs_packets = c->mfc_un.res.pkt;
  	mfcs.mfcs_bytes = c->mfc_un.res.bytes;
  	mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
  	if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2052
2053
  	rtm->rtm_type = RTN_MULTICAST;
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
  }
9a1b9496c   David S. Miller   ipv4: Pass explic...
2055
2056
2057
  int ipmr_get_route(struct net *net, struct sk_buff *skb,
  		   __be32 saddr, __be32 daddr,
  		   struct rtmsg *rtm, int nowait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
  	struct mfc_cache *cache;
9a1b9496c   David S. Miller   ipv4: Pass explic...
2060
2061
  	struct mr_table *mrt;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2063
2064
2065
  	mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return -ENOENT;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2066
  	rcu_read_lock();
9a1b9496c   David S. Miller   ipv4: Pass explic...
2067
  	cache = ipmr_cache_find(mrt, saddr, daddr);
660b26dc1   Nicolas Dichtel   mcast: add multic...
2068
2069
  	if (cache == NULL && skb->dev) {
  		int vif = ipmr_find_vif(mrt, skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2070

660b26dc1   Nicolas Dichtel   mcast: add multic...
2071
2072
2073
  		if (vif >= 0)
  			cache = ipmr_cache_find_any(mrt, daddr, vif);
  	}
c354e1246   Jianjun Kong   net: clean up net...
2074
  	if (cache == NULL) {
722874909   Alexey Kuznetsov   [IPV4] ipmr: ip m...
2075
  		struct sk_buff *skb2;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2076
  		struct iphdr *iph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2077
  		struct net_device *dev;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
2078
  		int vif = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2079
2080
  
  		if (nowait) {
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2081
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
2083
2084
2085
  			return -EAGAIN;
  		}
  
  		dev = skb->dev;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2086
  		read_lock(&mrt_lock);
a8cb16dd9   Eric Dumazet   ipmr: cleanups
2087
2088
2089
  		if (dev)
  			vif = ipmr_find_vif(mrt, dev);
  		if (vif < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2090
  			read_unlock(&mrt_lock);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2091
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
2093
  			return -ENODEV;
  		}
722874909   Alexey Kuznetsov   [IPV4] ipmr: ip m...
2094
2095
2096
  		skb2 = skb_clone(skb, GFP_ATOMIC);
  		if (!skb2) {
  			read_unlock(&mrt_lock);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2097
  			rcu_read_unlock();
722874909   Alexey Kuznetsov   [IPV4] ipmr: ip m...
2098
2099
  			return -ENOMEM;
  		}
e2d1bca7e   Arnaldo Carvalho de Melo   [SK_BUFF]: Use sk...
2100
2101
  		skb_push(skb2, sizeof(struct iphdr));
  		skb_reset_network_header(skb2);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2102
2103
  		iph = ip_hdr(skb2);
  		iph->ihl = sizeof(struct iphdr) >> 2;
9a1b9496c   David S. Miller   ipv4: Pass explic...
2104
2105
  		iph->saddr = saddr;
  		iph->daddr = daddr;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
2106
  		iph->version = 0;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2107
  		err = ipmr_cache_unresolved(mrt, vif, skb2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
  		read_unlock(&mrt_lock);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2109
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
2111
  		return err;
  	}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2112
2113
  	read_lock(&mrt_lock);
  	if (!nowait && (rtm->rtm_flags & RTM_F_NOTIFY))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114
  		cache->mfc_flags |= MFC_NOTIFY;
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2115
  	err = __ipmr_fill_mroute(mrt, skb, cache, rtm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2116
  	read_unlock(&mrt_lock);
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2117
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
2119
  	return err;
  }
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2120
  static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
2121
  			    u32 portid, u32 seq, struct mfc_cache *c, int cmd)
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2122
2123
2124
  {
  	struct nlmsghdr *nlh;
  	struct rtmsg *rtm;
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2125
  	int err;
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2126

8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
2127
  	nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2128
2129
2130
2131
2132
2133
2134
2135
2136
  	if (nlh == NULL)
  		return -EMSGSIZE;
  
  	rtm = nlmsg_data(nlh);
  	rtm->rtm_family   = RTNL_FAMILY_IPMR;
  	rtm->rtm_dst_len  = 32;
  	rtm->rtm_src_len  = 32;
  	rtm->rtm_tos      = 0;
  	rtm->rtm_table    = mrt->id;
f3756b79e   David S. Miller   ipv4: Stop using ...
2137
2138
  	if (nla_put_u32(skb, RTA_TABLE, mrt->id))
  		goto nla_put_failure;
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2139
2140
  	rtm->rtm_type     = RTN_MULTICAST;
  	rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
9a68ac72a   Nicolas Dichtel   ipmr/ip6mr: repor...
2141
2142
2143
2144
  	if (c->mfc_flags & MFC_STATIC)
  		rtm->rtm_protocol = RTPROT_STATIC;
  	else
  		rtm->rtm_protocol = RTPROT_MROUTED;
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2145
  	rtm->rtm_flags    = 0;
f3756b79e   David S. Miller   ipv4: Stop using ...
2146
2147
2148
  	if (nla_put_be32(skb, RTA_SRC, c->mfc_origin) ||
  	    nla_put_be32(skb, RTA_DST, c->mfc_mcastgrp))
  		goto nla_put_failure;
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2149
2150
2151
  	err = __ipmr_fill_mroute(mrt, skb, c, rtm);
  	/* do not break the dump if cache is unresolved */
  	if (err < 0 && err != -ENOENT)
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2152
2153
2154
2155
2156
2157
2158
2159
  		goto nla_put_failure;
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
  static size_t mroute_msgsize(bool unresolved, int maxvif)
  {
  	size_t len =
  		NLMSG_ALIGN(sizeof(struct rtmsg))
  		+ nla_total_size(4)	/* RTA_TABLE */
  		+ nla_total_size(4)	/* RTA_SRC */
  		+ nla_total_size(4)	/* 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 */
  		      + nla_total_size(sizeof(struct rta_mfc_stats))
  		;
  
  	return len;
  }
  
  static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
  				 int cmd)
  {
  	struct net *net = read_pnet(&mrt->net);
  	struct sk_buff *skb;
  	int err = -ENOBUFS;
  
  	skb = nlmsg_new(mroute_msgsize(mfc->mfc_parent >= MAXVIFS, mrt->maxvif),
  			GFP_ATOMIC);
  	if (skb == NULL)
  		goto errout;
  
  	err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
  	if (err < 0)
  		goto errout;
  
  	rtnl_notify(skb, net, 0, RTNLGRP_IPV4_MROUTE, NULL, GFP_ATOMIC);
  	return;
  
  errout:
  	kfree_skb(skb);
  	if (err < 0)
  		rtnl_set_sk_err(net, RTNLGRP_IPV4_MROUTE, err);
  }
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
  static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	struct net *net = sock_net(skb->sk);
  	struct mr_table *mrt;
  	struct mfc_cache *mfc;
  	unsigned int t = 0, s_t;
  	unsigned int h = 0, s_h;
  	unsigned int e = 0, s_e;
  
  	s_t = cb->args[0];
  	s_h = cb->args[1];
  	s_e = cb->args[2];
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2217
  	rcu_read_lock();
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2218
2219
2220
2221
2222
2223
  	ipmr_for_each_table(mrt, net) {
  		if (t < s_t)
  			goto next_table;
  		if (t > s_t)
  			s_h = 0;
  		for (h = s_h; h < MFC_LINES; h++) {
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2224
  			list_for_each_entry_rcu(mfc, &mrt->mfc_cache_array[h], list) {
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2225
2226
2227
  				if (e < s_e)
  					goto next_entry;
  				if (ipmr_fill_mroute(mrt, skb,
15e473046   Eric W. Biederman   netlink: Rename p...
2228
  						     NETLINK_CB(cb->skb).portid,
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2229
  						     cb->nlh->nlmsg_seq,
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
2230
  						     mfc, RTM_NEWROUTE) < 0)
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2231
2232
2233
2234
2235
2236
  					goto done;
  next_entry:
  				e++;
  			}
  			e = s_e = 0;
  		}
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2237
2238
2239
2240
2241
2242
2243
  		spin_lock_bh(&mfc_unres_lock);
  		list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
  			if (e < s_e)
  				goto next_entry2;
  			if (ipmr_fill_mroute(mrt, skb,
  					     NETLINK_CB(cb->skb).portid,
  					     cb->nlh->nlmsg_seq,
8cd3ac9f9   Nicolas Dichtel   ipmr: advertise n...
2244
  					     mfc, RTM_NEWROUTE) < 0) {
1eb99af52   Nicolas Dichtel   ipmr/ip6mr: allow...
2245
2246
2247
2248
2249
2250
2251
2252
  				spin_unlock_bh(&mfc_unres_lock);
  				goto done;
  			}
  next_entry2:
  			e++;
  		}
  		spin_unlock_bh(&mfc_unres_lock);
  		e = s_e = 0;
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2253
2254
2255
2256
2257
  		s_h = 0;
  next_table:
  		t++;
  	}
  done:
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2258
  	rcu_read_unlock();
cb6a4e461   Patrick McHardy   net: ipmr: add su...
2259
2260
2261
2262
2263
2264
2265
  
  	cb->args[2] = e;
  	cb->args[1] = h;
  	cb->args[0] = t;
  
  	return skb->len;
  }
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2266
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2267
  /*
a8cb16dd9   Eric Dumazet   ipmr: cleanups
2268
2269
   *	The /proc interfaces to multicast routing :
   *	/proc/net/ip_mr_cache & /proc/net/ip_mr_vif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
2271
   */
  struct ipmr_vif_iter {
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2272
  	struct seq_net_private p;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2273
  	struct mr_table *mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2274
2275
  	int ct;
  };
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2276
2277
  static struct vif_device *ipmr_vif_seq_idx(struct net *net,
  					   struct ipmr_vif_iter *iter,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2278
2279
  					   loff_t pos)
  {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2280
  	struct mr_table *mrt = iter->mrt;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2281
2282
2283
  
  	for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
  		if (!VIF_EXISTS(mrt, iter->ct))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
  			continue;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2285
  		if (pos-- == 0)
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2286
  			return &mrt->vif_table[iter->ct];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2287
2288
2289
2290
2291
  	}
  	return NULL;
  }
  
  static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
ba93ef746   Stephen Hemminger   [IPV4]: ipmr spar...
2292
  	__acquires(mrt_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
  {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2294
  	struct ipmr_vif_iter *iter = seq->private;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2295
  	struct net *net = seq_file_net(seq);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2296
2297
2298
2299
2300
2301
2302
  	struct mr_table *mrt;
  
  	mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return ERR_PTR(-ENOENT);
  
  	iter->mrt = mrt;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2303

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
  	read_lock(&mrt_lock);
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2305
  	return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
2307
2308
2309
2310
2311
  		: SEQ_START_TOKEN;
  }
  
  static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct ipmr_vif_iter *iter = seq->private;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2312
  	struct net *net = seq_file_net(seq);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2313
  	struct mr_table *mrt = iter->mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2314
2315
2316
  
  	++*pos;
  	if (v == SEQ_START_TOKEN)
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2317
  		return ipmr_vif_seq_idx(net, iter, 0);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2318

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2319
2320
  	while (++iter->ct < mrt->maxvif) {
  		if (!VIF_EXISTS(mrt, iter->ct))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321
  			continue;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2322
  		return &mrt->vif_table[iter->ct];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323
2324
2325
2326
2327
  	}
  	return NULL;
  }
  
  static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
ba93ef746   Stephen Hemminger   [IPV4]: ipmr spar...
2328
  	__releases(mrt_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2329
2330
2331
2332
2333
2334
  {
  	read_unlock(&mrt_lock);
  }
  
  static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
  {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2335
2336
  	struct ipmr_vif_iter *iter = seq->private;
  	struct mr_table *mrt = iter->mrt;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2337

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
  	if (v == SEQ_START_TOKEN) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2339
  		seq_puts(seq,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2340
2341
2342
2343
2344
2345
2346
2347
2348
  			 "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags Local    Remote
  ");
  	} else {
  		const struct vif_device *vif = v;
  		const char *name =  vif->dev ? vif->dev->name : "none";
  
  		seq_printf(seq,
  			   "%2Zd %-10s %8ld %7ld  %8ld %7ld %05X %08X %08X
  ",
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2349
  			   vif - mrt->vif_table,
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2350
  			   name, vif->bytes_in, vif->pkt_in,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2351
2352
2353
2354
2355
  			   vif->bytes_out, vif->pkt_out,
  			   vif->flags, vif->local, vif->remote);
  	}
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
2356
  static const struct seq_operations ipmr_vif_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
2358
2359
2360
2361
2362
2363
2364
  	.start = ipmr_vif_seq_start,
  	.next  = ipmr_vif_seq_next,
  	.stop  = ipmr_vif_seq_stop,
  	.show  = ipmr_vif_seq_show,
  };
  
  static int ipmr_vif_open(struct inode *inode, struct file *file)
  {
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2365
2366
  	return seq_open_net(inode, file, &ipmr_vif_seq_ops,
  			    sizeof(struct ipmr_vif_iter));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
2368
  static const struct file_operations ipmr_vif_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
2371
2372
  	.owner	 = THIS_MODULE,
  	.open    = ipmr_vif_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2373
  	.release = seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2374
2375
2376
  };
  
  struct ipmr_mfc_iter {
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2377
  	struct seq_net_private p;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2378
  	struct mr_table *mrt;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2379
  	struct list_head *cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
2381
  	int ct;
  };
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2382
2383
  static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
  					  struct ipmr_mfc_iter *it, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2384
  {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2385
  	struct mr_table *mrt = it->mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386
  	struct mfc_cache *mfc;
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2387
  	rcu_read_lock();
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2388
  	for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2389
  		it->cache = &mrt->mfc_cache_array[it->ct];
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2390
  		list_for_each_entry_rcu(mfc, it->cache, list)
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2391
  			if (pos-- == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2392
  				return mfc;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2393
  	}
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2394
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2395

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396
  	spin_lock_bh(&mfc_unres_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2397
  	it->cache = &mrt->mfc_unres_queue;
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2398
  	list_for_each_entry(mfc, it->cache, list)
e258beb22   Patrick McHardy   ipv4: ipmr: move ...
2399
  		if (pos-- == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
  			return mfc;
  	spin_unlock_bh(&mfc_unres_lock);
  
  	it->cache = NULL;
  	return NULL;
  }
  
  
  static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	struct ipmr_mfc_iter *it = seq->private;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2411
  	struct net *net = seq_file_net(seq);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2412
  	struct mr_table *mrt;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2413

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2414
2415
2416
  	mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
  	if (mrt == NULL)
  		return ERR_PTR(-ENOENT);
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2417

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2418
  	it->mrt = mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
2420
  	it->cache = NULL;
  	it->ct = 0;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2421
  	return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422
2423
2424
2425
2426
2427
2428
  		: SEQ_START_TOKEN;
  }
  
  static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct mfc_cache *mfc = v;
  	struct ipmr_mfc_iter *it = seq->private;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2429
  	struct net *net = seq_file_net(seq);
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2430
  	struct mr_table *mrt = it->mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431
2432
2433
2434
  
  	++*pos;
  
  	if (v == SEQ_START_TOKEN)
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2435
  		return ipmr_mfc_seq_idx(net, seq->private, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2436

862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2437
2438
  	if (mfc->list.next != it->cache)
  		return list_entry(mfc->list.next, struct mfc_cache, list);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2439

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2440
  	if (it->cache == &mrt->mfc_unres_queue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2441
  		goto end_of_list;
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2442
  	BUG_ON(it->cache != &mrt->mfc_cache_array[it->ct]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2443
2444
  
  	while (++it->ct < MFC_LINES) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2445
  		it->cache = &mrt->mfc_cache_array[it->ct];
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2446
2447
2448
  		if (list_empty(it->cache))
  			continue;
  		return list_first_entry(it->cache, struct mfc_cache, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2449
2450
2451
  	}
  
  	/* exhausted cache_array, show unresolved */
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2452
  	rcu_read_unlock();
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2453
  	it->cache = &mrt->mfc_unres_queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454
  	it->ct = 0;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2455

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2456
  	spin_lock_bh(&mfc_unres_lock);
862465f2e   Patrick McHardy   ipv4: ipmr: conve...
2457
2458
  	if (!list_empty(it->cache))
  		return list_first_entry(it->cache, struct mfc_cache, list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2459

a8cb16dd9   Eric Dumazet   ipmr: cleanups
2460
  end_of_list:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2461
2462
2463
2464
2465
2466
2467
2468
2469
  	spin_unlock_bh(&mfc_unres_lock);
  	it->cache = NULL;
  
  	return NULL;
  }
  
  static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
  {
  	struct ipmr_mfc_iter *it = seq->private;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2470
  	struct mr_table *mrt = it->mrt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2471

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2472
  	if (it->cache == &mrt->mfc_unres_queue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2473
  		spin_unlock_bh(&mfc_unres_lock);
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2474
  	else if (it->cache == &mrt->mfc_cache_array[it->ct])
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2475
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2476
2477
2478
2479
2480
2481
2482
  }
  
  static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
  {
  	int n;
  
  	if (v == SEQ_START_TOKEN) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2483
  		seq_puts(seq,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
2485
2486
2487
2488
  		 "Group    Origin   Iif     Pkts    Bytes    Wrong Oifs
  ");
  	} else {
  		const struct mfc_cache *mfc = v;
  		const struct ipmr_mfc_iter *it = seq->private;
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2489
  		const struct mr_table *mrt = it->mrt;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2490

0eae88f31   Eric Dumazet   net: Fix various ...
2491
2492
2493
  		seq_printf(seq, "%08X %08X %-3hd",
  			   (__force u32) mfc->mfc_mcastgrp,
  			   (__force u32) mfc->mfc_origin,
1ea472e2d   Benjamin Thery   net: fix /proc/ne...
2494
  			   mfc->mfc_parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2495

0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2496
  		if (it->cache != &mrt->mfc_unres_queue) {
1ea472e2d   Benjamin Thery   net: fix /proc/ne...
2497
2498
2499
2500
  			seq_printf(seq, " %8lu %8lu %8lu",
  				   mfc->mfc_un.res.pkt,
  				   mfc->mfc_un.res.bytes,
  				   mfc->mfc_un.res.wrong_if);
132adf546   Stephen Hemminger   [IPV4]: cleanup
2501
  			for (n = mfc->mfc_un.res.minvif;
a8cb16dd9   Eric Dumazet   ipmr: cleanups
2502
  			     n < mfc->mfc_un.res.maxvif; n++) {
0c12295a7   Patrick McHardy   ipv4: ipmr: move ...
2503
  				if (VIF_EXISTS(mrt, n) &&
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2504
2505
  				    mfc->mfc_un.res.ttls[n] < 255)
  					seq_printf(seq,
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2506
  					   " %2d:%-3d",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507
2508
  					   n, mfc->mfc_un.res.ttls[n]);
  			}
1ea472e2d   Benjamin Thery   net: fix /proc/ne...
2509
2510
2511
2512
2513
  		} else {
  			/* unresolved mfc_caches don't contain
  			 * pkt, bytes and wrong_if values
  			 */
  			seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2514
2515
2516
2517
2518
2519
  		}
  		seq_putc(seq, '
  ');
  	}
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
2520
  static const struct seq_operations ipmr_mfc_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2521
2522
2523
2524
2525
2526
2527
2528
  	.start = ipmr_mfc_seq_start,
  	.next  = ipmr_mfc_seq_next,
  	.stop  = ipmr_mfc_seq_stop,
  	.show  = ipmr_mfc_seq_show,
  };
  
  static int ipmr_mfc_open(struct inode *inode, struct file *file)
  {
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2529
2530
  	return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
  			    sizeof(struct ipmr_mfc_iter));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2531
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
2532
  static const struct file_operations ipmr_mfc_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2533
2534
2535
2536
  	.owner	 = THIS_MODULE,
  	.open    = ipmr_mfc_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2537
  	.release = seq_release_net,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
  };
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2539
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2540
2541
  
  #ifdef CONFIG_IP_PIMSM_V2
32613090a   Alexey Dobriyan   net: constify str...
2542
  static const struct net_protocol pim_protocol = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2543
  	.handler	=	pim_rcv,
403dbb97f   Tom Goff   PIM-SM: namespace...
2544
  	.netns_ok	=	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
2546
2547
2548
2549
2550
2551
  };
  #endif
  
  
  /*
   *	Setup for IP multicast routing
   */
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2552
2553
  static int __net_init ipmr_net_init(struct net *net)
  {
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2554
  	int err;
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2555

f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2556
2557
  	err = ipmr_rules_init(net);
  	if (err < 0)
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2558
  		goto fail;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2559
2560
2561
  
  #ifdef CONFIG_PROC_FS
  	err = -ENOMEM;
d4beaa66a   Gao feng   net: proc: change...
2562
  	if (!proc_create("ip_mr_vif", 0, net->proc_net, &ipmr_vif_fops))
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2563
  		goto proc_vif_fail;
d4beaa66a   Gao feng   net: proc: change...
2564
  	if (!proc_create("ip_mr_cache", 0, net->proc_net, &ipmr_mfc_fops))
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2565
2566
  		goto proc_cache_fail;
  #endif
2bb8b26c3   Benjamin Thery   netns: ipmr: dyna...
2567
  	return 0;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2568
2569
  #ifdef CONFIG_PROC_FS
  proc_cache_fail:
ece31ffd5   Gao feng   net: proc: change...
2570
  	remove_proc_entry("ip_mr_vif", net->proc_net);
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2571
  proc_vif_fail:
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2572
  	ipmr_rules_exit(net);
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2573
  #endif
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2574
2575
2576
2577
2578
2579
  fail:
  	return err;
  }
  
  static void __net_exit ipmr_net_exit(struct net *net)
  {
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2580
  #ifdef CONFIG_PROC_FS
ece31ffd5   Gao feng   net: proc: change...
2581
2582
  	remove_proc_entry("ip_mr_cache", net->proc_net);
  	remove_proc_entry("ip_mr_vif", net->proc_net);
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2583
  #endif
f0ad0860d   Patrick McHardy   ipv4: ipmr: suppo...
2584
  	ipmr_rules_exit(net);
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2585
2586
2587
2588
2589
2590
  }
  
  static struct pernet_operations ipmr_net_ops = {
  	.init = ipmr_net_init,
  	.exit = ipmr_net_exit,
  };
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
2591

03d2f897e   Wang Chen   ipv4: Do cleanup ...
2592
  int __init ip_mr_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2593
  {
03d2f897e   Wang Chen   ipv4: Do cleanup ...
2594
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2595
2596
  	mrt_cachep = kmem_cache_create("ip_mrt_cache",
  				       sizeof(struct mfc_cache),
a8c9486b8   Eric Dumazet   ipmr: RCU protect...
2597
  				       0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
20c2df83d   Paul Mundt   mm: Remove slab d...
2598
  				       NULL);
03d2f897e   Wang Chen   ipv4: Do cleanup ...
2599
2600
  	if (!mrt_cachep)
  		return -ENOMEM;
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2601
2602
2603
  	err = register_pernet_subsys(&ipmr_net_ops);
  	if (err)
  		goto reg_pernet_fail;
03d2f897e   Wang Chen   ipv4: Do cleanup ...
2604
2605
2606
  	err = register_netdevice_notifier(&ip_mr_notifier);
  	if (err)
  		goto reg_notif_fail;
403dbb97f   Tom Goff   PIM-SM: namespace...
2607
2608
  #ifdef CONFIG_IP_PIMSM_V2
  	if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
058bd4d2a   Joe Perches   net: Convert prin...
2609
2610
  		pr_err("%s: can't add PIM protocol
  ", __func__);
403dbb97f   Tom Goff   PIM-SM: namespace...
2611
2612
2613
2614
  		err = -EAGAIN;
  		goto add_proto_fail;
  	}
  #endif
c7ac8679b   Greg Rose   rtnetlink: Comput...
2615
2616
  	rtnl_register(RTNL_FAMILY_IPMR, RTM_GETROUTE,
  		      NULL, ipmr_rtm_dumproute, NULL);
03d2f897e   Wang Chen   ipv4: Do cleanup ...
2617
  	return 0;
f6bb45147   Benjamin Thery   netns: ipmr: decl...
2618

403dbb97f   Tom Goff   PIM-SM: namespace...
2619
2620
2621
2622
  #ifdef CONFIG_IP_PIMSM_V2
  add_proto_fail:
  	unregister_netdevice_notifier(&ip_mr_notifier);
  #endif
c3e388964   Benjamin Thery   net: fix ip_mr_in...
2623
  reg_notif_fail:
cf958ae37   Benjamin Thery   netns: ipmr: dyna...
2624
2625
  	unregister_pernet_subsys(&ipmr_net_ops);
  reg_pernet_fail:
c3e388964   Benjamin Thery   net: fix ip_mr_in...
2626
  	kmem_cache_destroy(mrt_cachep);
03d2f897e   Wang Chen   ipv4: Do cleanup ...
2627
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2628
  }