blob: e2db2ea616ff9400d31f813aae36ccd47704bc88 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * IP multicast routing support for mrouted 3.6/3.8
3 *
Alan Cox113aa832008-10-13 19:01:08 -07004 * (c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Linux Consultancy and Custom Driver Development
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Fixes:
13 * Michael Chastain : Incorrect size of copying.
14 * Alan Cox : Added the cache manager code
15 * Alan Cox : Fixed the clone/copy bug and device race.
16 * Mike McLagan : Routing by source
17 * Malcolm Beattie : Buffer handling fixes.
18 * Alexey Kuznetsov : Double buffer free and other fixes.
19 * SVR Anand : Fixed several multicast bugs and problems.
20 * Alexey Kuznetsov : Status, optimisations and more.
21 * Brad Parker : Better behaviour on mrouted upcall
22 * overflow.
23 * Carlos Picoto : PIMv1 Support
24 * Pavlin Ivanov Radoslavov: PIMv2 Registers must checksum only PIM header
Gilles Espinassef77f13e2010-03-29 15:41:47 +020025 * Relax this requirement to work with older peers.
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 *
27 */
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/system.h>
30#include <asm/uaccess.h>
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/timer.h>
35#include <linux/mm.h>
36#include <linux/kernel.h>
37#include <linux/fcntl.h>
38#include <linux/stat.h>
39#include <linux/socket.h>
40#include <linux/in.h>
41#include <linux/inet.h>
42#include <linux/netdevice.h>
43#include <linux/inetdevice.h>
44#include <linux/igmp.h>
45#include <linux/proc_fs.h>
46#include <linux/seq_file.h>
47#include <linux/mroute.h>
48#include <linux/init.h>
Kris Katterjohn46f25df2006-01-05 16:35:42 -080049#include <linux/if_ether.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090050#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020051#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/ip.h>
53#include <net/protocol.h>
54#include <linux/skbuff.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020055#include <net/route.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <net/sock.h>
57#include <net/icmp.h>
58#include <net/udp.h>
59#include <net/raw.h>
60#include <linux/notifier.h>
61#include <linux/if_arp.h>
62#include <linux/netfilter_ipv4.h>
63#include <net/ipip.h>
64#include <net/checksum.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070065#include <net/netlink.h>
Patrick McHardyf0ad0862010-04-13 05:03:23 +000066#include <net/fib_rules.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
69#define CONFIG_IP_PIMSM 1
70#endif
71
Patrick McHardy0c122952010-04-13 05:03:22 +000072struct mr_table {
Patrick McHardyf0ad0862010-04-13 05:03:23 +000073 struct list_head list;
Patrick McHardy8de53df2010-04-15 13:29:28 +020074#ifdef CONFIG_NET_NS
75 struct net *net;
76#endif
Patrick McHardyf0ad0862010-04-13 05:03:23 +000077 u32 id;
Eric Dumazet4c9687092010-10-01 16:15:01 +000078 struct sock __rcu *mroute_sk;
Patrick McHardy0c122952010-04-13 05:03:22 +000079 struct timer_list ipmr_expire_timer;
80 struct list_head mfc_unres_queue;
81 struct list_head mfc_cache_array[MFC_LINES];
82 struct vif_device vif_table[MAXVIFS];
83 int maxvif;
84 atomic_t cache_resolve_queue_len;
85 int mroute_do_assert;
86 int mroute_do_pim;
87#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
88 int mroute_reg_vif_num;
89#endif
90};
91
Patrick McHardyf0ad0862010-04-13 05:03:23 +000092struct ipmr_rule {
93 struct fib_rule common;
94};
95
96struct ipmr_result {
97 struct mr_table *mrt;
98};
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* Big lock, protecting vif table, mrt cache and mroute socket state.
101 Note that the changes are semaphored via rtnl_lock.
102 */
103
104static DEFINE_RWLOCK(mrt_lock);
105
106/*
107 * Multicast router control variables
108 */
109
Patrick McHardy0c122952010-04-13 05:03:22 +0000110#define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112/* Special spinlock for queue of unresolved entries */
113static DEFINE_SPINLOCK(mfc_unres_lock);
114
115/* We return to original Alan's scheme. Hash table of resolved
116 entries is changed only in process context and protected
117 with weak lock mrt_lock. Queue of unresolved entries is protected
118 with strong spinlock mfc_unres_lock.
119
120 In this case data path is free of exclusive locks at all.
121 */
122
Christoph Lametere18b8902006-12-06 20:33:20 -0800123static struct kmem_cache *mrt_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000125static struct mr_table *ipmr_new_table(struct net *net, u32 id);
Patrick McHardy0c122952010-04-13 05:03:22 +0000126static int ip_mr_forward(struct net *net, struct mr_table *mrt,
127 struct sk_buff *skb, struct mfc_cache *cache,
128 int local);
129static int ipmr_cache_report(struct mr_table *mrt,
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000130 struct sk_buff *pkt, vifi_t vifi, int assert);
Patrick McHardycb6a4e42010-04-26 16:02:08 +0200131static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
132 struct mfc_cache *c, struct rtmsg *rtm);
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000133static void ipmr_expire_process(unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000135#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
136#define ipmr_for_each_table(mrt, net) \
137 list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list)
138
139static struct mr_table *ipmr_get_table(struct net *net, u32 id)
140{
141 struct mr_table *mrt;
142
143 ipmr_for_each_table(mrt, net) {
144 if (mrt->id == id)
145 return mrt;
146 }
147 return NULL;
148}
149
150static int ipmr_fib_lookup(struct net *net, struct flowi *flp,
151 struct mr_table **mrt)
152{
153 struct ipmr_result res;
154 struct fib_lookup_arg arg = { .result = &res, };
155 int err;
156
157 err = fib_rules_lookup(net->ipv4.mr_rules_ops, flp, 0, &arg);
158 if (err < 0)
159 return err;
160 *mrt = res.mrt;
161 return 0;
162}
163
164static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
165 int flags, struct fib_lookup_arg *arg)
166{
167 struct ipmr_result *res = arg->result;
168 struct mr_table *mrt;
169
170 switch (rule->action) {
171 case FR_ACT_TO_TBL:
172 break;
173 case FR_ACT_UNREACHABLE:
174 return -ENETUNREACH;
175 case FR_ACT_PROHIBIT:
176 return -EACCES;
177 case FR_ACT_BLACKHOLE:
178 default:
179 return -EINVAL;
180 }
181
182 mrt = ipmr_get_table(rule->fr_net, rule->table);
183 if (mrt == NULL)
184 return -EAGAIN;
185 res->mrt = mrt;
186 return 0;
187}
188
189static int ipmr_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
190{
191 return 1;
192}
193
194static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = {
195 FRA_GENERIC_POLICY,
196};
197
198static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
199 struct fib_rule_hdr *frh, struct nlattr **tb)
200{
201 return 0;
202}
203
204static int ipmr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
205 struct nlattr **tb)
206{
207 return 1;
208}
209
210static int ipmr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
211 struct fib_rule_hdr *frh)
212{
213 frh->dst_len = 0;
214 frh->src_len = 0;
215 frh->tos = 0;
216 return 0;
217}
218
Patrick McHardy3d0c9c42010-04-26 16:02:04 +0200219static const struct fib_rules_ops __net_initdata ipmr_rules_ops_template = {
Patrick McHardy25239ce2010-04-26 16:02:05 +0200220 .family = RTNL_FAMILY_IPMR,
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000221 .rule_size = sizeof(struct ipmr_rule),
222 .addr_size = sizeof(u32),
223 .action = ipmr_rule_action,
224 .match = ipmr_rule_match,
225 .configure = ipmr_rule_configure,
226 .compare = ipmr_rule_compare,
227 .default_pref = fib_default_rule_pref,
228 .fill = ipmr_rule_fill,
229 .nlgroup = RTNLGRP_IPV4_RULE,
230 .policy = ipmr_rule_policy,
231 .owner = THIS_MODULE,
232};
233
234static int __net_init ipmr_rules_init(struct net *net)
235{
236 struct fib_rules_ops *ops;
237 struct mr_table *mrt;
238 int err;
239
240 ops = fib_rules_register(&ipmr_rules_ops_template, net);
241 if (IS_ERR(ops))
242 return PTR_ERR(ops);
243
244 INIT_LIST_HEAD(&net->ipv4.mr_tables);
245
246 mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
247 if (mrt == NULL) {
248 err = -ENOMEM;
249 goto err1;
250 }
251
252 err = fib_default_rule_add(ops, 0x7fff, RT_TABLE_DEFAULT, 0);
253 if (err < 0)
254 goto err2;
255
256 net->ipv4.mr_rules_ops = ops;
257 return 0;
258
259err2:
260 kfree(mrt);
261err1:
262 fib_rules_unregister(ops);
263 return err;
264}
265
266static void __net_exit ipmr_rules_exit(struct net *net)
267{
268 struct mr_table *mrt, *next;
269
Eric Dumazet035320d2010-06-06 23:48:40 +0000270 list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
271 list_del(&mrt->list);
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000272 kfree(mrt);
Eric Dumazet035320d2010-06-06 23:48:40 +0000273 }
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000274 fib_rules_unregister(net->ipv4.mr_rules_ops);
275}
276#else
277#define ipmr_for_each_table(mrt, net) \
278 for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
279
280static struct mr_table *ipmr_get_table(struct net *net, u32 id)
281{
282 return net->ipv4.mrt;
283}
284
285static int ipmr_fib_lookup(struct net *net, struct flowi *flp,
286 struct mr_table **mrt)
287{
288 *mrt = net->ipv4.mrt;
289 return 0;
290}
291
292static int __net_init ipmr_rules_init(struct net *net)
293{
294 net->ipv4.mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
295 return net->ipv4.mrt ? 0 : -ENOMEM;
296}
297
298static void __net_exit ipmr_rules_exit(struct net *net)
299{
300 kfree(net->ipv4.mrt);
301}
302#endif
303
304static struct mr_table *ipmr_new_table(struct net *net, u32 id)
305{
306 struct mr_table *mrt;
307 unsigned int i;
308
309 mrt = ipmr_get_table(net, id);
310 if (mrt != NULL)
311 return mrt;
312
313 mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
314 if (mrt == NULL)
315 return NULL;
Patrick McHardy8de53df2010-04-15 13:29:28 +0200316 write_pnet(&mrt->net, net);
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000317 mrt->id = id;
318
319 /* Forwarding cache */
320 for (i = 0; i < MFC_LINES; i++)
321 INIT_LIST_HEAD(&mrt->mfc_cache_array[i]);
322
323 INIT_LIST_HEAD(&mrt->mfc_unres_queue);
324
325 setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
326 (unsigned long)mrt);
327
328#ifdef CONFIG_IP_PIMSM
329 mrt->mroute_reg_vif_num = -1;
330#endif
331#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
332 list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables);
333#endif
334 return mrt;
335}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
338
Wang Chend6070322008-07-14 20:55:26 -0700339static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
340{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000341 struct net *net = dev_net(dev);
342
Wang Chend6070322008-07-14 20:55:26 -0700343 dev_close(dev);
344
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000345 dev = __dev_get_by_name(net, "tunl0");
Wang Chend6070322008-07-14 20:55:26 -0700346 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800347 const struct net_device_ops *ops = dev->netdev_ops;
Wang Chend6070322008-07-14 20:55:26 -0700348 struct ifreq ifr;
Wang Chend6070322008-07-14 20:55:26 -0700349 struct ip_tunnel_parm p;
350
351 memset(&p, 0, sizeof(p));
352 p.iph.daddr = v->vifc_rmt_addr.s_addr;
353 p.iph.saddr = v->vifc_lcl_addr.s_addr;
354 p.iph.version = 4;
355 p.iph.ihl = 5;
356 p.iph.protocol = IPPROTO_IPIP;
357 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
358 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
359
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800360 if (ops->ndo_do_ioctl) {
361 mm_segment_t oldfs = get_fs();
362
363 set_fs(KERNEL_DS);
364 ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
365 set_fs(oldfs);
366 }
Wang Chend6070322008-07-14 20:55:26 -0700367 }
368}
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370static
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000371struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 struct net_device *dev;
374
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000375 dev = __dev_get_by_name(net, "tunl0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800378 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 int err;
380 struct ifreq ifr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 struct ip_tunnel_parm p;
382 struct in_device *in_dev;
383
384 memset(&p, 0, sizeof(p));
385 p.iph.daddr = v->vifc_rmt_addr.s_addr;
386 p.iph.saddr = v->vifc_lcl_addr.s_addr;
387 p.iph.version = 4;
388 p.iph.ihl = 5;
389 p.iph.protocol = IPPROTO_IPIP;
390 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
Stephen Hemmingerba93ef72008-01-21 17:28:59 -0800391 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800393 if (ops->ndo_do_ioctl) {
394 mm_segment_t oldfs = get_fs();
395
396 set_fs(KERNEL_DS);
397 err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
398 set_fs(oldfs);
399 } else
400 err = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 dev = NULL;
403
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000404 if (err == 0 &&
405 (dev = __dev_get_by_name(net, p.name)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 dev->flags |= IFF_MULTICAST;
407
Herbert Xue5ed6392005-10-03 14:35:55 -0700408 in_dev = __in_dev_get_rtnl(dev);
Herbert Xu71e27da2007-06-04 23:36:06 -0700409 if (in_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700411
412 ipv4_devconf_setall(in_dev);
413 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 if (dev_open(dev))
416 goto failure;
Wang Chen7dc00c82008-07-14 20:56:34 -0700417 dev_hold(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419 }
420 return dev;
421
422failure:
423 /* allow the register to be completed before unregistering. */
424 rtnl_unlock();
425 rtnl_lock();
426
427 unregister_netdevice(dev);
428 return NULL;
429}
430
431#ifdef CONFIG_IP_PIMSM
432
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000433static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000435 struct net *net = dev_net(dev);
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000436 struct mr_table *mrt;
437 struct flowi fl = {
438 .oif = dev->ifindex,
439 .iif = skb->skb_iif,
440 .mark = skb->mark,
441 };
442 int err;
443
444 err = ipmr_fib_lookup(net, &fl, &mrt);
Ben Greeare40dbc52010-07-15 13:22:33 +0000445 if (err < 0) {
446 kfree_skb(skb);
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000447 return err;
Ben Greeare40dbc52010-07-15 13:22:33 +0000448 }
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 read_lock(&mrt_lock);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700451 dev->stats.tx_bytes += skb->len;
452 dev->stats.tx_packets++;
Patrick McHardy0c122952010-04-13 05:03:22 +0000453 ipmr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, IGMPMSG_WHOLEPKT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 read_unlock(&mrt_lock);
455 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000456 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Stephen Hemminger007c3832008-11-20 20:28:35 -0800459static const struct net_device_ops reg_vif_netdev_ops = {
460 .ndo_start_xmit = reg_vif_xmit,
461};
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463static void reg_vif_setup(struct net_device *dev)
464{
465 dev->type = ARPHRD_PIMREG;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800466 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800468 dev->netdev_ops = &reg_vif_netdev_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700470 dev->features |= NETIF_F_NETNS_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471}
472
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000473static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 struct net_device *dev;
476 struct in_device *in_dev;
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000477 char name[IFNAMSIZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000479 if (mrt->id == RT_TABLE_DEFAULT)
480 sprintf(name, "pimreg");
481 else
482 sprintf(name, "pimreg%u", mrt->id);
483
484 dev = alloc_netdev(0, name, reg_vif_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 if (dev == NULL)
487 return NULL;
488
Tom Goff403dbb92009-06-14 03:16:13 -0700489 dev_net_set(dev, net);
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (register_netdevice(dev)) {
492 free_netdev(dev);
493 return NULL;
494 }
495 dev->iflink = 0;
496
Herbert Xu71e27da2007-06-04 23:36:06 -0700497 rcu_read_lock();
498 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
499 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Herbert Xu71e27da2007-06-04 23:36:06 -0700503 ipv4_devconf_setall(in_dev);
504 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
505 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 if (dev_open(dev))
508 goto failure;
509
Wang Chen7dc00c82008-07-14 20:56:34 -0700510 dev_hold(dev);
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return dev;
513
514failure:
515 /* allow the register to be completed before unregistering. */
516 rtnl_unlock();
517 rtnl_lock();
518
519 unregister_netdevice(dev);
520 return NULL;
521}
522#endif
523
524/*
525 * Delete a VIF entry
Wang Chen7dc00c82008-07-14 20:56:34 -0700526 * @notify: Set to 1, if the caller is a notifier_call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900528
Patrick McHardy0c122952010-04-13 05:03:22 +0000529static int vif_delete(struct mr_table *mrt, int vifi, int notify,
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000530 struct list_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
532 struct vif_device *v;
533 struct net_device *dev;
534 struct in_device *in_dev;
535
Patrick McHardy0c122952010-04-13 05:03:22 +0000536 if (vifi < 0 || vifi >= mrt->maxvif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return -EADDRNOTAVAIL;
538
Patrick McHardy0c122952010-04-13 05:03:22 +0000539 v = &mrt->vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 write_lock_bh(&mrt_lock);
542 dev = v->dev;
543 v->dev = NULL;
544
545 if (!dev) {
546 write_unlock_bh(&mrt_lock);
547 return -EADDRNOTAVAIL;
548 }
549
550#ifdef CONFIG_IP_PIMSM
Patrick McHardy0c122952010-04-13 05:03:22 +0000551 if (vifi == mrt->mroute_reg_vif_num)
552 mrt->mroute_reg_vif_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553#endif
554
Patrick McHardy0c122952010-04-13 05:03:22 +0000555 if (vifi+1 == mrt->maxvif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 int tmp;
557 for (tmp=vifi-1; tmp>=0; tmp--) {
Patrick McHardy0c122952010-04-13 05:03:22 +0000558 if (VIF_EXISTS(mrt, tmp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 break;
560 }
Patrick McHardy0c122952010-04-13 05:03:22 +0000561 mrt->maxvif = tmp+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
563
564 write_unlock_bh(&mrt_lock);
565
566 dev_set_allmulti(dev, -1);
567
Herbert Xue5ed6392005-10-03 14:35:55 -0700568 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Herbert Xu42f811b2007-06-04 23:34:44 -0700569 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 ip_rt_multicast_event(in_dev);
571 }
572
Wang Chen7dc00c82008-07-14 20:56:34 -0700573 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000574 unregister_netdevice_queue(dev, head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 dev_put(dev);
577 return 0;
578}
579
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000580static inline void ipmr_cache_free(struct mfc_cache *c)
581{
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000582 kmem_cache_free(mrt_cachep, c);
583}
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585/* Destroy an unresolved cache entry, killing queued skbs
586 and reporting error to netlink readers.
587 */
588
Patrick McHardy0c122952010-04-13 05:03:22 +0000589static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
Patrick McHardy8de53df2010-04-15 13:29:28 +0200591 struct net *net = read_pnet(&mrt->net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700593 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Patrick McHardy0c122952010-04-13 05:03:22 +0000595 atomic_dec(&mrt->cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Jianjun Kongc354e122008-11-03 00:28:02 -0800597 while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700598 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
600 nlh->nlmsg_type = NLMSG_ERROR;
601 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
602 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700603 e = NLMSG_DATA(nlh);
604 e->error = -ETIMEDOUT;
605 memset(&e->msg, 0, sizeof(e->msg));
Thomas Graf2942e902006-08-15 00:30:25 -0700606
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000607 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 } else
609 kfree_skb(skb);
610 }
611
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000612 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613}
614
615
Patrick McHardye258beb2010-04-13 05:03:19 +0000616/* Timer process for the unresolved queue. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Patrick McHardye258beb2010-04-13 05:03:19 +0000618static void ipmr_expire_process(unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Patrick McHardy0c122952010-04-13 05:03:22 +0000620 struct mr_table *mrt = (struct mr_table *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 unsigned long now;
622 unsigned long expires;
Patrick McHardy862465f2010-04-13 05:03:21 +0000623 struct mfc_cache *c, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardy0c122952010-04-13 05:03:22 +0000626 mod_timer(&mrt->ipmr_expire_timer, jiffies+HZ/10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return;
628 }
629
Patrick McHardy0c122952010-04-13 05:03:22 +0000630 if (list_empty(&mrt->mfc_unres_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 goto out;
632
633 now = jiffies;
634 expires = 10*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Patrick McHardy0c122952010-04-13 05:03:22 +0000636 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (time_after(c->mfc_un.unres.expires, now)) {
638 unsigned long interval = c->mfc_un.unres.expires - now;
639 if (interval < expires)
640 expires = interval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 continue;
642 }
643
Patrick McHardy862465f2010-04-13 05:03:21 +0000644 list_del(&c->list);
Patrick McHardy0c122952010-04-13 05:03:22 +0000645 ipmr_destroy_unres(mrt, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
Patrick McHardy0c122952010-04-13 05:03:22 +0000648 if (!list_empty(&mrt->mfc_unres_queue))
649 mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651out:
652 spin_unlock(&mfc_unres_lock);
653}
654
655/* Fill oifs list. It is called under write locked mrt_lock. */
656
Patrick McHardy0c122952010-04-13 05:03:22 +0000657static void ipmr_update_thresholds(struct mr_table *mrt, struct mfc_cache *cache,
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000658 unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
660 int vifi;
661
662 cache->mfc_un.res.minvif = MAXVIFS;
663 cache->mfc_un.res.maxvif = 0;
664 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
665
Patrick McHardy0c122952010-04-13 05:03:22 +0000666 for (vifi = 0; vifi < mrt->maxvif; vifi++) {
667 if (VIF_EXISTS(mrt, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000668 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
670 if (cache->mfc_un.res.minvif > vifi)
671 cache->mfc_un.res.minvif = vifi;
672 if (cache->mfc_un.res.maxvif <= vifi)
673 cache->mfc_un.res.maxvif = vifi + 1;
674 }
675 }
676}
677
Patrick McHardy0c122952010-04-13 05:03:22 +0000678static int vif_add(struct net *net, struct mr_table *mrt,
679 struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 int vifi = vifc->vifc_vifi;
Patrick McHardy0c122952010-04-13 05:03:22 +0000682 struct vif_device *v = &mrt->vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 struct net_device *dev;
684 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700685 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 /* Is vif busy ? */
Patrick McHardy0c122952010-04-13 05:03:22 +0000688 if (VIF_EXISTS(mrt, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return -EADDRINUSE;
690
691 switch (vifc->vifc_flags) {
692#ifdef CONFIG_IP_PIMSM
693 case VIFF_REGISTER:
694 /*
695 * Special Purpose VIF in PIM
696 * All the packets will be sent to the daemon
697 */
Patrick McHardy0c122952010-04-13 05:03:22 +0000698 if (mrt->mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return -EADDRINUSE;
Patrick McHardyf0ad0862010-04-13 05:03:23 +0000700 dev = ipmr_reg_vif(net, mrt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (!dev)
702 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700703 err = dev_set_allmulti(dev, 1);
704 if (err) {
705 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700706 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700707 return err;
708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 break;
710#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900711 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000712 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (!dev)
714 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700715 err = dev_set_allmulti(dev, 1);
716 if (err) {
717 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700718 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700719 return err;
720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 break;
Ilia Kee5e81f2009-09-16 05:53:07 +0000722
723 case VIFF_USE_IFINDEX:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 case 0:
Ilia Kee5e81f2009-09-16 05:53:07 +0000725 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
726 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
Eric Dumazet95ae6b22010-09-15 04:04:31 +0000727 if (dev && __in_dev_get_rtnl(dev) == NULL) {
Ilia Kee5e81f2009-09-16 05:53:07 +0000728 dev_put(dev);
729 return -EADDRNOTAVAIL;
730 }
731 } else
732 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (!dev)
735 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700736 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700737 if (err) {
738 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700739 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 break;
742 default:
743 return -EINVAL;
744 }
745
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000746 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
747 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000749 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700750 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 ip_rt_multicast_event(in_dev);
752
753 /*
754 * Fill in the VIF structures
755 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800756 v->rate_limit = vifc->vifc_rate_limit;
757 v->local = vifc->vifc_lcl_addr.s_addr;
758 v->remote = vifc->vifc_rmt_addr.s_addr;
759 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (!mrtsock)
761 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800762 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 v->bytes_in = 0;
764 v->bytes_out = 0;
765 v->pkt_in = 0;
766 v->pkt_out = 0;
767 v->link = dev->ifindex;
768 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
769 v->link = dev->iflink;
770
771 /* And finish update writing critical data */
772 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800773 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774#ifdef CONFIG_IP_PIMSM
775 if (v->flags&VIFF_REGISTER)
Patrick McHardy0c122952010-04-13 05:03:22 +0000776 mrt->mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#endif
Patrick McHardy0c122952010-04-13 05:03:22 +0000778 if (vifi+1 > mrt->maxvif)
779 mrt->maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 write_unlock_bh(&mrt_lock);
781 return 0;
782}
783
Patrick McHardy0c122952010-04-13 05:03:22 +0000784static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000785 __be32 origin,
786 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787{
Jianjun Kongc354e122008-11-03 00:28:02 -0800788 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 struct mfc_cache *c;
790
Patrick McHardy0c122952010-04-13 05:03:22 +0000791 list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
Patrick McHardy862465f2010-04-13 05:03:21 +0000792 if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
793 return c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
Patrick McHardy862465f2010-04-13 05:03:21 +0000795 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796}
797
798/*
799 * Allocate a multicast cache entry
800 */
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000801static struct mfc_cache *ipmr_cache_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
Jianjun Kongc354e122008-11-03 00:28:02 -0800803 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
804 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 c->mfc_un.res.minvif = MAXVIFS;
807 return c;
808}
809
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000810static struct mfc_cache *ipmr_cache_alloc_unres(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
Jianjun Kongc354e122008-11-03 00:28:02 -0800812 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
813 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 skb_queue_head_init(&c->mfc_un.unres.unresolved);
816 c->mfc_un.unres.expires = jiffies + 10*HZ;
817 return c;
818}
819
820/*
821 * A cache entry has gone into a resolved state from queued
822 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900823
Patrick McHardy0c122952010-04-13 05:03:22 +0000824static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
825 struct mfc_cache *uc, struct mfc_cache *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
827 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700828 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830 /*
831 * Play the pending entries through our router
832 */
833
Jianjun Kongc354e122008-11-03 00:28:02 -0800834 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700835 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
837
Patrick McHardycb6a4e42010-04-26 16:02:08 +0200838 if (__ipmr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700839 nlh->nlmsg_len = (skb_tail_pointer(skb) -
840 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 } else {
842 nlh->nlmsg_type = NLMSG_ERROR;
843 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
844 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700845 e = NLMSG_DATA(nlh);
846 e->error = -EMSGSIZE;
847 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
Thomas Graf2942e902006-08-15 00:30:25 -0700849
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000850 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 } else
Patrick McHardy0c122952010-04-13 05:03:22 +0000852 ip_mr_forward(net, mrt, skb, c, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854}
855
856/*
857 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
858 * expects the following bizarre scheme.
859 *
860 * Called under mrt_lock.
861 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900862
Patrick McHardy0c122952010-04-13 05:03:22 +0000863static int ipmr_cache_report(struct mr_table *mrt,
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000864 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300867 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 struct igmphdr *igmp;
869 struct igmpmsg *msg;
Eric Dumazet4c9687092010-10-01 16:15:01 +0000870 struct sock *mroute_sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 int ret;
872
873#ifdef CONFIG_IP_PIMSM
874 if (assert == IGMPMSG_WHOLEPKT)
875 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
876 else
877#endif
878 skb = alloc_skb(128, GFP_ATOMIC);
879
Stephen Hemminger132adf52007-03-08 20:44:43 -0800880 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return -ENOBUFS;
882
883#ifdef CONFIG_IP_PIMSM
884 if (assert == IGMPMSG_WHOLEPKT) {
885 /* Ugly, but we have no choice with this interface.
886 Duplicate old header, fix ihl, length etc.
887 And all this only to mangle msg->im_msgtype and
888 to set msg->im_mbz to "mbz" :-)
889 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300890 skb_push(skb, sizeof(struct iphdr));
891 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300892 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300893 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700894 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 msg->im_msgtype = IGMPMSG_WHOLEPKT;
896 msg->im_mbz = 0;
Patrick McHardy0c122952010-04-13 05:03:22 +0000897 msg->im_vif = mrt->mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700898 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
899 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
900 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900901 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900903 {
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /*
906 * Copy the IP header
907 */
908
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700909 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300910 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300911 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700912 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
913 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000915 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 /*
918 * Add our header
919 */
920
Jianjun Kongc354e122008-11-03 00:28:02 -0800921 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 igmp->type =
923 msg->im_msgtype = assert;
924 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700925 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700926 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Eric Dumazet4c9687092010-10-01 16:15:01 +0000929 rcu_read_lock();
930 mroute_sk = rcu_dereference(mrt->mroute_sk);
931 if (mroute_sk == NULL) {
932 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 kfree_skb(skb);
934 return -EINVAL;
935 }
936
937 /*
938 * Deliver to mrouted
939 */
Eric Dumazet4c9687092010-10-01 16:15:01 +0000940 ret = sock_queue_rcv_skb(mroute_sk, skb);
941 rcu_read_unlock();
Benjamin Thery70a269e2009-01-22 04:56:15 +0000942 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 if (net_ratelimit())
944 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
945 kfree_skb(skb);
946 }
947
948 return ret;
949}
950
951/*
952 * Queue a packet for resolution. It gets locked cache entry!
953 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955static int
Patrick McHardy0c122952010-04-13 05:03:22 +0000956ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
Patrick McHardy862465f2010-04-13 05:03:21 +0000958 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 int err;
960 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700961 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +0000964 list_for_each_entry(c, &mrt->mfc_unres_queue, list) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000965 if (c->mfc_mcastgrp == iph->daddr &&
Patrick McHardy862465f2010-04-13 05:03:21 +0000966 c->mfc_origin == iph->saddr) {
967 found = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 break;
Patrick McHardy862465f2010-04-13 05:03:21 +0000969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 }
971
Patrick McHardy862465f2010-04-13 05:03:21 +0000972 if (!found) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /*
974 * Create a new entry if allowable
975 */
976
Patrick McHardy0c122952010-04-13 05:03:22 +0000977 if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000978 (c = ipmr_cache_alloc_unres()) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 spin_unlock_bh(&mfc_unres_lock);
980
981 kfree_skb(skb);
982 return -ENOBUFS;
983 }
984
985 /*
986 * Fill in the new cache entry
987 */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700988 c->mfc_parent = -1;
989 c->mfc_origin = iph->saddr;
990 c->mfc_mcastgrp = iph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 /*
993 * Reflect first query at mrouted.
994 */
Patrick McHardy0c122952010-04-13 05:03:22 +0000995 err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000996 if (err < 0) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900997 /* If the report failed throw the cache entry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 out - Brad Parker
999 */
1000 spin_unlock_bh(&mfc_unres_lock);
1001
Benjamin Thery5c0a66f2009-01-22 04:56:17 +00001002 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 kfree_skb(skb);
1004 return err;
1005 }
1006
Patrick McHardy0c122952010-04-13 05:03:22 +00001007 atomic_inc(&mrt->cache_resolve_queue_len);
1008 list_add(&c->list, &mrt->mfc_unres_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
David S. Miller278554b2010-05-12 00:05:35 -07001010 if (atomic_read(&mrt->cache_resolve_queue_len) == 1)
1011 mod_timer(&mrt->ipmr_expire_timer, c->mfc_un.unres.expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 }
1013
1014 /*
1015 * See if we can append the packet
1016 */
1017 if (c->mfc_un.unres.unresolved.qlen>3) {
1018 kfree_skb(skb);
1019 err = -ENOBUFS;
1020 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -08001021 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 err = 0;
1023 }
1024
1025 spin_unlock_bh(&mfc_unres_lock);
1026 return err;
1027}
1028
1029/*
1030 * MFC cache manipulation by user space mroute daemon
1031 */
1032
Patrick McHardy0c122952010-04-13 05:03:22 +00001033static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
1035 int line;
Patrick McHardy862465f2010-04-13 05:03:21 +00001036 struct mfc_cache *c, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Jianjun Kongc354e122008-11-03 00:28:02 -08001038 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Patrick McHardy0c122952010-04-13 05:03:22 +00001040 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
1042 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
1043 write_lock_bh(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001044 list_del(&c->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 write_unlock_bh(&mrt_lock);
1046
Benjamin Thery5c0a66f2009-01-22 04:56:17 +00001047 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return 0;
1049 }
1050 }
1051 return -ENOENT;
1052}
1053
Patrick McHardy0c122952010-04-13 05:03:22 +00001054static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
1055 struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Patrick McHardy862465f2010-04-13 05:03:21 +00001057 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 int line;
Patrick McHardy862465f2010-04-13 05:03:21 +00001059 struct mfc_cache *uc, *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Patrick McHardya50436f22010-03-17 06:04:14 +00001061 if (mfc->mfcc_parent >= MAXVIFS)
1062 return -ENFILE;
1063
Jianjun Kongc354e122008-11-03 00:28:02 -08001064 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Patrick McHardy0c122952010-04-13 05:03:22 +00001066 list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
Patrick McHardy862465f2010-04-13 05:03:21 +00001068 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
1069 found = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 break;
Patrick McHardy862465f2010-04-13 05:03:21 +00001071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073
Patrick McHardy862465f2010-04-13 05:03:21 +00001074 if (found) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 write_lock_bh(&mrt_lock);
1076 c->mfc_parent = mfc->mfcc_parent;
Patrick McHardy0c122952010-04-13 05:03:22 +00001077 ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if (!mrtsock)
1079 c->mfc_flags |= MFC_STATIC;
1080 write_unlock_bh(&mrt_lock);
1081 return 0;
1082 }
1083
Joe Perchesf97c1e02007-12-16 13:45:43 -08001084 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return -EINVAL;
1086
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001087 c = ipmr_cache_alloc();
Jianjun Kongc354e122008-11-03 00:28:02 -08001088 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return -ENOMEM;
1090
Jianjun Kongc354e122008-11-03 00:28:02 -08001091 c->mfc_origin = mfc->mfcc_origin.s_addr;
1092 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
1093 c->mfc_parent = mfc->mfcc_parent;
Patrick McHardy0c122952010-04-13 05:03:22 +00001094 ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (!mrtsock)
1096 c->mfc_flags |= MFC_STATIC;
1097
1098 write_lock_bh(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001099 list_add(&c->list, &mrt->mfc_cache_array[line]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 write_unlock_bh(&mrt_lock);
1101
1102 /*
1103 * Check to see if we resolved a queued list. If so we
1104 * need to send on the frames and tidy up.
1105 */
Patrick McHardyb0ebb732010-04-15 13:29:28 +02001106 found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001108 list_for_each_entry(uc, &mrt->mfc_unres_queue, list) {
Patrick McHardye258beb2010-04-13 05:03:19 +00001109 if (uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
Patrick McHardy862465f2010-04-13 05:03:21 +00001111 list_del(&uc->list);
Patrick McHardy0c122952010-04-13 05:03:22 +00001112 atomic_dec(&mrt->cache_resolve_queue_len);
Patrick McHardyb0ebb732010-04-15 13:29:28 +02001113 found = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 break;
1115 }
1116 }
Patrick McHardy0c122952010-04-13 05:03:22 +00001117 if (list_empty(&mrt->mfc_unres_queue))
1118 del_timer(&mrt->ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 spin_unlock_bh(&mfc_unres_lock);
1120
Patrick McHardyb0ebb732010-04-15 13:29:28 +02001121 if (found) {
Patrick McHardy0c122952010-04-13 05:03:22 +00001122 ipmr_cache_resolve(net, mrt, uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +00001123 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
1125 return 0;
1126}
1127
1128/*
1129 * Close the multicast socket, and clear the vif tables etc
1130 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001131
Patrick McHardy0c122952010-04-13 05:03:22 +00001132static void mroute_clean_tables(struct mr_table *mrt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
1134 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001135 LIST_HEAD(list);
Patrick McHardy862465f2010-04-13 05:03:21 +00001136 struct mfc_cache *c, *next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 /*
1139 * Shut down all active vif entries
1140 */
Patrick McHardy0c122952010-04-13 05:03:22 +00001141 for (i = 0; i < mrt->maxvif; i++) {
1142 if (!(mrt->vif_table[i].flags&VIFF_STATIC))
1143 vif_delete(mrt, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001145 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 /*
1148 * Wipe the cache
1149 */
Patrick McHardy862465f2010-04-13 05:03:21 +00001150 for (i = 0; i < MFC_LINES; i++) {
Patrick McHardy0c122952010-04-13 05:03:22 +00001151 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
Patrick McHardy862465f2010-04-13 05:03:21 +00001152 if (c->mfc_flags&MFC_STATIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 write_lock_bh(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001155 list_del(&c->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 write_unlock_bh(&mrt_lock);
1157
Benjamin Thery5c0a66f2009-01-22 04:56:17 +00001158 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 }
1161
Patrick McHardy0c122952010-04-13 05:03:22 +00001162 if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001164 list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
Patrick McHardy862465f2010-04-13 05:03:21 +00001165 list_del(&c->list);
Patrick McHardy0c122952010-04-13 05:03:22 +00001166 ipmr_destroy_unres(mrt, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168 spin_unlock_bh(&mfc_unres_lock);
1169 }
1170}
1171
Eric Dumazet4c9687092010-10-01 16:15:01 +00001172/* called from ip_ra_control(), before an RCU grace period,
1173 * we dont need to call synchronize_rcu() here
1174 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175static void mrtsock_destruct(struct sock *sk)
1176{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001177 struct net *net = sock_net(sk);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001178 struct mr_table *mrt;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 rtnl_lock();
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001181 ipmr_for_each_table(mrt, net) {
Eric Dumazet4c9687092010-10-01 16:15:01 +00001182 if (sk == rtnl_dereference(mrt->mroute_sk)) {
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001183 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Eric Dumazet4c9687092010-10-01 16:15:01 +00001184 rcu_assign_pointer(mrt->mroute_sk, NULL);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001185 mroute_clean_tables(mrt);
1186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188 rtnl_unlock();
1189}
1190
1191/*
1192 * Socket options and virtual interface manipulation. The whole
1193 * virtual interface system is a complete heap, but unfortunately
1194 * that's how BSD mrouted happens to think. Maybe one day with a proper
1195 * MOSPF/PIM router set up we can clean this up.
1196 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001197
David S. Millerb7058842009-09-30 16:12:20 -07001198int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 int ret;
1201 struct vifctl vif;
1202 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001203 struct net *net = sock_net(sk);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001204 struct mr_table *mrt;
1205
1206 mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1207 if (mrt == NULL)
1208 return -ENOENT;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001209
Stephen Hemminger132adf52007-03-08 20:44:43 -08001210 if (optname != MRT_INIT) {
Eric Dumazet4c9687092010-10-01 16:15:01 +00001211 if (sk != rcu_dereference_raw(mrt->mroute_sk) &&
1212 !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 return -EACCES;
1214 }
1215
Stephen Hemminger132adf52007-03-08 20:44:43 -08001216 switch (optname) {
1217 case MRT_INIT:
1218 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e82009-10-15 06:30:45 +00001219 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001220 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -08001221 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001222 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Stephen Hemminger132adf52007-03-08 20:44:43 -08001224 rtnl_lock();
Eric Dumazet4c9687092010-10-01 16:15:01 +00001225 if (rtnl_dereference(mrt->mroute_sk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -08001227 return -EADDRINUSE;
1228 }
1229
1230 ret = ip_ra_control(sk, 1, mrtsock_destruct);
1231 if (ret == 0) {
Eric Dumazet4c9687092010-10-01 16:15:01 +00001232 rcu_assign_pointer(mrt->mroute_sk, sk);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001233 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001234 }
1235 rtnl_unlock();
1236 return ret;
1237 case MRT_DONE:
Eric Dumazet4c9687092010-10-01 16:15:01 +00001238 if (sk != rcu_dereference_raw(mrt->mroute_sk))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001239 return -EACCES;
1240 return ip_ra_control(sk, 0, NULL);
1241 case MRT_ADD_VIF:
1242 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -08001243 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001244 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001245 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001246 return -EFAULT;
1247 if (vif.vifc_vifi >= MAXVIFS)
1248 return -ENFILE;
1249 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001250 if (optname == MRT_ADD_VIF) {
Eric Dumazet4c9687092010-10-01 16:15:01 +00001251 ret = vif_add(net, mrt, &vif,
1252 sk == rtnl_dereference(mrt->mroute_sk));
Stephen Hemminger132adf52007-03-08 20:44:43 -08001253 } else {
Patrick McHardy0c122952010-04-13 05:03:22 +00001254 ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001255 }
1256 rtnl_unlock();
1257 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259 /*
1260 * Manipulate the forwarding caches. These live
1261 * in a sort of kernel/user symbiosis.
1262 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001263 case MRT_ADD_MFC:
1264 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -08001265 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001266 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001267 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001268 return -EFAULT;
1269 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001270 if (optname == MRT_DEL_MFC)
Patrick McHardy0c122952010-04-13 05:03:22 +00001271 ret = ipmr_mfc_delete(mrt, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001272 else
Eric Dumazet4c9687092010-10-01 16:15:01 +00001273 ret = ipmr_mfc_add(net, mrt, &mfc,
1274 sk == rtnl_dereference(mrt->mroute_sk));
Stephen Hemminger132adf52007-03-08 20:44:43 -08001275 rtnl_unlock();
1276 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 /*
1278 * Control PIM assert.
1279 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001280 case MRT_ASSERT:
1281 {
1282 int v;
1283 if (get_user(v,(int __user *)optval))
1284 return -EFAULT;
Patrick McHardy0c122952010-04-13 05:03:22 +00001285 mrt->mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001286 return 0;
1287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001289 case MRT_PIM:
1290 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001291 int v;
1292
Stephen Hemminger132adf52007-03-08 20:44:43 -08001293 if (get_user(v,(int __user *)optval))
1294 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001295 v = (v) ? 1 : 0;
1296
Stephen Hemminger132adf52007-03-08 20:44:43 -08001297 rtnl_lock();
1298 ret = 0;
Patrick McHardy0c122952010-04-13 05:03:22 +00001299 if (v != mrt->mroute_do_pim) {
1300 mrt->mroute_do_pim = v;
1301 mrt->mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001303 rtnl_unlock();
1304 return ret;
1305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306#endif
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001307#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
1308 case MRT_TABLE:
1309 {
1310 u32 v;
1311
1312 if (optlen != sizeof(u32))
1313 return -EINVAL;
1314 if (get_user(v, (u32 __user *)optval))
1315 return -EFAULT;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001316
1317 rtnl_lock();
1318 ret = 0;
Eric Dumazet4c9687092010-10-01 16:15:01 +00001319 if (sk == rtnl_dereference(mrt->mroute_sk)) {
1320 ret = -EBUSY;
1321 } else {
1322 if (!ipmr_new_table(net, v))
1323 ret = -ENOMEM;
1324 raw_sk(sk)->ipmr_table = v;
1325 }
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001326 rtnl_unlock();
1327 return ret;
1328 }
1329#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001330 /*
1331 * Spurious command, or MRT_VERSION which you cannot
1332 * set.
1333 */
1334 default:
1335 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337}
1338
1339/*
1340 * Getsock opt support for the multicast routing system.
1341 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001342
Jianjun Kongc354e122008-11-03 00:28:02 -08001343int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
1345 int olr;
1346 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001347 struct net *net = sock_net(sk);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001348 struct mr_table *mrt;
1349
1350 mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1351 if (mrt == NULL)
1352 return -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Jianjun Kongc354e122008-11-03 00:28:02 -08001354 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355#ifdef CONFIG_IP_PIMSM
1356 optname!=MRT_PIM &&
1357#endif
1358 optname!=MRT_ASSERT)
1359 return -ENOPROTOOPT;
1360
1361 if (get_user(olr, optlen))
1362 return -EFAULT;
1363
1364 olr = min_t(unsigned int, olr, sizeof(int));
1365 if (olr < 0)
1366 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001367
Jianjun Kongc354e122008-11-03 00:28:02 -08001368 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001370 if (optname == MRT_VERSION)
1371 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001373 else if (optname == MRT_PIM)
Patrick McHardy0c122952010-04-13 05:03:22 +00001374 val = mrt->mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375#endif
1376 else
Patrick McHardy0c122952010-04-13 05:03:22 +00001377 val = mrt->mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001378 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 return -EFAULT;
1380 return 0;
1381}
1382
1383/*
1384 * The IP multicast ioctl support routines.
1385 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1388{
1389 struct sioc_sg_req sr;
1390 struct sioc_vif_req vr;
1391 struct vif_device *vif;
1392 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001393 struct net *net = sock_net(sk);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001394 struct mr_table *mrt;
1395
1396 mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1397 if (mrt == NULL)
1398 return -ENOENT;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001399
Stephen Hemminger132adf52007-03-08 20:44:43 -08001400 switch (cmd) {
1401 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001402 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001403 return -EFAULT;
Patrick McHardy0c122952010-04-13 05:03:22 +00001404 if (vr.vifi >= mrt->maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001405 return -EINVAL;
1406 read_lock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001407 vif = &mrt->vif_table[vr.vifi];
1408 if (VIF_EXISTS(mrt, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001409 vr.icount = vif->pkt_in;
1410 vr.ocount = vif->pkt_out;
1411 vr.ibytes = vif->bytes_in;
1412 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001414
Jianjun Kongc354e122008-11-03 00:28:02 -08001415 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001417 return 0;
1418 }
1419 read_unlock(&mrt_lock);
1420 return -EADDRNOTAVAIL;
1421 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001422 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001423 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Stephen Hemminger132adf52007-03-08 20:44:43 -08001425 read_lock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001426 c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001427 if (c) {
1428 sr.pktcnt = c->mfc_un.res.pkt;
1429 sr.bytecnt = c->mfc_un.res.bytes;
1430 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001432
Jianjun Kongc354e122008-11-03 00:28:02 -08001433 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001434 return -EFAULT;
1435 return 0;
1436 }
1437 read_unlock(&mrt_lock);
1438 return -EADDRNOTAVAIL;
1439 default:
1440 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 }
1442}
1443
1444
1445static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1446{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001447 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001448 struct net *net = dev_net(dev);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001449 struct mr_table *mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 struct vif_device *v;
1451 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001452 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 if (event != NETDEV_UNREGISTER)
1455 return NOTIFY_DONE;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001456
1457 ipmr_for_each_table(mrt, net) {
1458 v = &mrt->vif_table[0];
1459 for (ct = 0; ct < mrt->maxvif; ct++, v++) {
1460 if (v->dev == dev)
1461 vif_delete(mrt, ct, 1, &list);
1462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001464 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 return NOTIFY_DONE;
1466}
1467
1468
Jianjun Kongc354e122008-11-03 00:28:02 -08001469static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 .notifier_call = ipmr_device_event,
1471};
1472
1473/*
1474 * Encapsulate a packet by attaching a valid IPIP header to it.
1475 * This avoids tunnel drivers and other mess and gives us the speed so
1476 * important for multicast video.
1477 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001478
Al Viro114c7842006-09-27 18:39:29 -07001479static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001481 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001482 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001483
1484 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001485 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001486 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001487 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001490 iph->tos = old_iph->tos;
1491 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 iph->frag_off = 0;
1493 iph->daddr = daddr;
1494 iph->saddr = saddr;
1495 iph->protocol = IPPROTO_IPIP;
1496 iph->ihl = 5;
1497 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001498 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 ip_send_check(iph);
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1502 nf_reset(skb);
1503}
1504
1505static inline int ipmr_forward_finish(struct sk_buff *skb)
1506{
1507 struct ip_options * opt = &(IPCB(skb)->opt);
1508
Eric Dumazetadf30902009-06-02 05:19:30 +00001509 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
1511 if (unlikely(opt->optlen))
1512 ip_forward_options(skb);
1513
1514 return dst_output(skb);
1515}
1516
1517/*
1518 * Processing handlers for ipmr_forward
1519 */
1520
Patrick McHardy0c122952010-04-13 05:03:22 +00001521static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
1522 struct sk_buff *skb, struct mfc_cache *c, int vifi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001524 const struct iphdr *iph = ip_hdr(skb);
Patrick McHardy0c122952010-04-13 05:03:22 +00001525 struct vif_device *vif = &mrt->vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 struct net_device *dev;
1527 struct rtable *rt;
1528 int encap = 0;
1529
1530 if (vif->dev == NULL)
1531 goto out_free;
1532
1533#ifdef CONFIG_IP_PIMSM
1534 if (vif->flags & VIFF_REGISTER) {
1535 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001536 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001537 vif->dev->stats.tx_bytes += skb->len;
1538 vif->dev->stats.tx_packets++;
Patrick McHardy0c122952010-04-13 05:03:22 +00001539 ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001540 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 }
1542#endif
1543
1544 if (vif->flags&VIFF_TUNNEL) {
1545 struct flowi fl = { .oif = vif->link,
1546 .nl_u = { .ip4_u =
1547 { .daddr = vif->remote,
1548 .saddr = vif->local,
1549 .tos = RT_TOS(iph->tos) } },
1550 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001551 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 goto out_free;
1553 encap = sizeof(struct iphdr);
1554 } else {
1555 struct flowi fl = { .oif = vif->link,
1556 .nl_u = { .ip4_u =
1557 { .daddr = iph->daddr,
1558 .tos = RT_TOS(iph->tos) } },
1559 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001560 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 goto out_free;
1562 }
1563
Changli Gaod8d1f302010-06-10 23:31:35 -07001564 dev = rt->dst.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Changli Gaod8d1f302010-06-10 23:31:35 -07001566 if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* Do not fragment multicasts. Alas, IPv4 does not
1568 allow to send ICMP, so that packets will disappear
1569 to blackhole.
1570 */
1571
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001572 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 ip_rt_put(rt);
1574 goto out_free;
1575 }
1576
Changli Gaod8d1f302010-06-10 23:31:35 -07001577 encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001580 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 goto out_free;
1582 }
1583
1584 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001585 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
Eric Dumazetadf30902009-06-02 05:19:30 +00001587 skb_dst_drop(skb);
Changli Gaod8d1f302010-06-10 23:31:35 -07001588 skb_dst_set(skb, &rt->dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001589 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 /* FIXME: forward and output firewalls used to be called here.
1592 * What do we do with netfilter? -- RR */
1593 if (vif->flags & VIFF_TUNNEL) {
1594 ip_encap(skb, vif->local, vif->remote);
1595 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001596 vif->dev->stats.tx_packets++;
1597 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 }
1599
1600 IPCB(skb)->flags |= IPSKB_FORWARDED;
1601
1602 /*
1603 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1604 * not only before forwarding, but after forwarding on all output
1605 * interfaces. It is clear, if mrouter runs a multicasting
1606 * program, it should receive packets not depending to what interface
1607 * program is joined.
1608 * If we will not make it, the program will have to join on all
1609 * interfaces. On the other hand, multihoming host (or router, but
1610 * not mrouter) cannot join to more than one interface - it will
1611 * result in receiving multiple packets.
1612 */
Jan Engelhardt9bbc7682010-03-23 04:07:29 +01001613 NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 ipmr_forward_finish);
1615 return;
1616
1617out_free:
1618 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619}
1620
Patrick McHardy0c122952010-04-13 05:03:22 +00001621static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 int ct;
Patrick McHardy0c122952010-04-13 05:03:22 +00001624
1625 for (ct = mrt->maxvif-1; ct >= 0; ct--) {
1626 if (mrt->vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 break;
1628 }
1629 return ct;
1630}
1631
1632/* "local" means that we should preserve one skb (for local delivery) */
1633
Patrick McHardy0c122952010-04-13 05:03:22 +00001634static int ip_mr_forward(struct net *net, struct mr_table *mrt,
1635 struct sk_buff *skb, struct mfc_cache *cache,
1636 int local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637{
1638 int psend = -1;
1639 int vif, ct;
1640
1641 vif = cache->mfc_parent;
1642 cache->mfc_un.res.pkt++;
1643 cache->mfc_un.res.bytes += skb->len;
1644
1645 /*
1646 * Wrong interface: drop packet and (maybe) send PIM assert.
1647 */
Patrick McHardy0c122952010-04-13 05:03:22 +00001648 if (mrt->vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 int true_vifi;
1650
Eric Dumazet511c3f92009-06-02 05:14:27 +00001651 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 /* It is our own packet, looped back.
1653 Very complicated situation...
1654
1655 The best workaround until routing daemons will be
1656 fixed is not to redistribute packet, if it was
1657 send through wrong interface. It means, that
1658 multicast applications WILL NOT work for
1659 (S,G), which have default multicast route pointing
1660 to wrong oif. In any case, it is not a good
1661 idea to use multicasting applications on router.
1662 */
1663 goto dont_forward;
1664 }
1665
1666 cache->mfc_un.res.wrong_if++;
Patrick McHardy0c122952010-04-13 05:03:22 +00001667 true_vifi = ipmr_find_vif(mrt, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Patrick McHardy0c122952010-04-13 05:03:22 +00001669 if (true_vifi >= 0 && mrt->mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 /* pimsm uses asserts, when switching from RPT to SPT,
1671 so that we cannot check that packet arrived on an oif.
1672 It is bad, but otherwise we would need to move pretty
1673 large chunk of pimd to kernel. Ough... --ANK
1674 */
Patrick McHardy0c122952010-04-13 05:03:22 +00001675 (mrt->mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001676 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001677 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1679 cache->mfc_un.res.last_assert = jiffies;
Patrick McHardy0c122952010-04-13 05:03:22 +00001680 ipmr_cache_report(mrt, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
1682 goto dont_forward;
1683 }
1684
Patrick McHardy0c122952010-04-13 05:03:22 +00001685 mrt->vif_table[vif].pkt_in++;
1686 mrt->vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 /*
1689 * Forward the frame
1690 */
1691 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001692 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (psend != -1) {
1694 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1695 if (skb2)
Patrick McHardy0c122952010-04-13 05:03:22 +00001696 ipmr_queue_xmit(net, mrt, skb2, cache,
1697 psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001699 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 }
1701 }
1702 if (psend != -1) {
1703 if (local) {
1704 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1705 if (skb2)
Patrick McHardy0c122952010-04-13 05:03:22 +00001706 ipmr_queue_xmit(net, mrt, skb2, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 } else {
Patrick McHardy0c122952010-04-13 05:03:22 +00001708 ipmr_queue_xmit(net, mrt, skb, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 return 0;
1710 }
1711 }
1712
1713dont_forward:
1714 if (!local)
1715 kfree_skb(skb);
1716 return 0;
1717}
1718
1719
1720/*
1721 * Multicast packets for forwarding arrive here
Eric Dumazet4c9687092010-10-01 16:15:01 +00001722 * Called with rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 */
1724
1725int ip_mr_input(struct sk_buff *skb)
1726{
1727 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001728 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001729 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001730 struct mr_table *mrt;
1731 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 /* Packet is looped back after forward, it should not be
1734 forwarded second time, but still can be delivered locally.
1735 */
Eric Dumazet4c9687092010-10-01 16:15:01 +00001736 if (IPCB(skb)->flags & IPSKB_FORWARDED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 goto dont_forward;
1738
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001739 err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt);
Ben Greeare40dbc52010-07-15 13:22:33 +00001740 if (err < 0) {
1741 kfree_skb(skb);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001742 return err;
Ben Greeare40dbc52010-07-15 13:22:33 +00001743 }
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if (!local) {
Eric Dumazet4c9687092010-10-01 16:15:01 +00001746 if (IPCB(skb)->opt.router_alert) {
1747 if (ip_call_ra_chain(skb))
1748 return 0;
1749 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP) {
1750 /* IGMPv1 (and broken IGMPv2 implementations sort of
1751 * Cisco IOS <= 11.2(8)) do not put router alert
1752 * option to IGMP packets destined to routable
1753 * groups. It is very bad, because it means
1754 * that we can forward NO IGMP messages.
1755 */
1756 struct sock *mroute_sk;
1757
1758 mroute_sk = rcu_dereference(mrt->mroute_sk);
1759 if (mroute_sk) {
1760 nf_reset(skb);
1761 raw_rcv(mroute_sk, skb);
1762 return 0;
1763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 }
1765 }
1766
1767 read_lock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001768 cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
1770 /*
1771 * No usable cache entry
1772 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001773 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 int vif;
1775
1776 if (local) {
1777 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1778 ip_local_deliver(skb);
1779 if (skb2 == NULL) {
1780 read_unlock(&mrt_lock);
1781 return -ENOBUFS;
1782 }
1783 skb = skb2;
1784 }
1785
Patrick McHardy0c122952010-04-13 05:03:22 +00001786 vif = ipmr_find_vif(mrt, skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 if (vif >= 0) {
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001788 int err2 = ipmr_cache_unresolved(mrt, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 read_unlock(&mrt_lock);
1790
Eric Dumazet0eae88f2010-04-20 19:06:52 -07001791 return err2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 }
1793 read_unlock(&mrt_lock);
1794 kfree_skb(skb);
1795 return -ENODEV;
1796 }
1797
Patrick McHardy0c122952010-04-13 05:03:22 +00001798 ip_mr_forward(net, mrt, skb, cache, local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800 read_unlock(&mrt_lock);
1801
1802 if (local)
1803 return ip_local_deliver(skb);
1804
1805 return 0;
1806
1807dont_forward:
1808 if (local)
1809 return ip_local_deliver(skb);
1810 kfree_skb(skb);
1811 return 0;
1812}
1813
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001814#ifdef CONFIG_IP_PIMSM
Eric Dumazet55747a02010-10-01 16:14:55 +00001815/* called with rcu_read_lock() */
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001816static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
1817 unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001819 struct net_device *reg_dev = NULL;
1820 struct iphdr *encap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001822 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 /*
1824 Check that:
1825 a. packet is really destinted to a multicast group
1826 b. packet is not a NULL-REGISTER
1827 c. packet is not truncated
1828 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001829 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001831 ntohs(encap->tot_len) + pimlen > skb->len)
1832 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
1834 read_lock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001835 if (mrt->mroute_reg_vif_num >= 0)
1836 reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 read_unlock(&mrt_lock);
1838
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001839 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001840 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001842 skb->mac_header = skb->network_header;
Eric Dumazet55747a02010-10-01 16:14:55 +00001843 skb_pull(skb, (u8 *)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001844 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 skb->protocol = htons(ETH_P_IP);
Eric Dumazet55747a02010-10-01 16:14:55 +00001846 skb->ip_summed = CHECKSUM_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 skb->pkt_type = PACKET_HOST;
Eric Dumazetd19d56d2010-05-17 22:36:55 -07001848
1849 skb_tunnel_rx(skb, reg_dev);
1850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 netif_rx(skb);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001852
Eric Dumazet55747a02010-10-01 16:14:55 +00001853 return NET_RX_SUCCESS;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001854}
1855#endif
1856
1857#ifdef CONFIG_IP_PIMSM_V1
1858/*
1859 * Handle IGMP messages of PIMv1
1860 */
1861
1862int pim_rcv_v1(struct sk_buff * skb)
1863{
1864 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001865 struct net *net = dev_net(skb->dev);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001866 struct mr_table *mrt;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001867
1868 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1869 goto drop;
1870
1871 pim = igmp_hdr(skb);
1872
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001873 if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
1874 goto drop;
1875
Patrick McHardy0c122952010-04-13 05:03:22 +00001876 if (!mrt->mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001877 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1878 goto drop;
1879
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001880 if (__pim_rcv(mrt, skb, sizeof(*pim))) {
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001881drop:
1882 kfree_skb(skb);
1883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return 0;
1885}
1886#endif
1887
1888#ifdef CONFIG_IP_PIMSM_V2
1889static int pim_rcv(struct sk_buff * skb)
1890{
1891 struct pimreghdr *pim;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001892 struct net *net = dev_net(skb->dev);
1893 struct mr_table *mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001895 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 goto drop;
1897
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001898 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001899 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001901 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001902 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 goto drop;
1904
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001905 if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
1906 goto drop;
1907
1908 if (__pim_rcv(mrt, skb, sizeof(*pim))) {
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001909drop:
1910 kfree_skb(skb);
1911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 return 0;
1913}
1914#endif
1915
Patrick McHardycb6a4e42010-04-26 16:02:08 +02001916static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
1917 struct mfc_cache *c, struct rtmsg *rtm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
1919 int ct;
1920 struct rtnexthop *nhp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001921 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 struct rtattr *mp_head;
1923
Nicolas Dichtel74381892010-03-25 23:45:35 +00001924 /* If cache is unresolved, don't try to parse IIF and OIF */
Dan Carpentered0f160a2010-05-26 00:38:56 -07001925 if (c->mfc_parent >= MAXVIFS)
Nicolas Dichtel74381892010-03-25 23:45:35 +00001926 return -ENOENT;
1927
Patrick McHardy0c122952010-04-13 05:03:22 +00001928 if (VIF_EXISTS(mrt, c->mfc_parent))
1929 RTA_PUT(skb, RTA_IIF, 4, &mrt->vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Jianjun Kongc354e122008-11-03 00:28:02 -08001931 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
1933 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Patrick McHardy0c122952010-04-13 05:03:22 +00001934 if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1936 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001937 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 nhp->rtnh_flags = 0;
1939 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Patrick McHardy0c122952010-04-13 05:03:22 +00001940 nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 nhp->rtnh_len = sizeof(*nhp);
1942 }
1943 }
1944 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001945 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 rtm->rtm_type = RTN_MULTICAST;
1947 return 1;
1948
1949rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001950 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 return -EMSGSIZE;
1952}
1953
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001954int ipmr_get_route(struct net *net,
1955 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956{
1957 int err;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001958 struct mr_table *mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001960 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
Patrick McHardyf0ad0862010-04-13 05:03:23 +00001962 mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
1963 if (mrt == NULL)
1964 return -ENOENT;
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 read_lock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00001967 cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Jianjun Kongc354e122008-11-03 00:28:02 -08001969 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001970 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001971 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 struct net_device *dev;
1973 int vif;
1974
1975 if (nowait) {
1976 read_unlock(&mrt_lock);
1977 return -EAGAIN;
1978 }
1979
1980 dev = skb->dev;
Patrick McHardy0c122952010-04-13 05:03:22 +00001981 if (dev == NULL || (vif = ipmr_find_vif(mrt, dev)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 read_unlock(&mrt_lock);
1983 return -ENODEV;
1984 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001985 skb2 = skb_clone(skb, GFP_ATOMIC);
1986 if (!skb2) {
1987 read_unlock(&mrt_lock);
1988 return -ENOMEM;
1989 }
1990
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001991 skb_push(skb2, sizeof(struct iphdr));
1992 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001993 iph = ip_hdr(skb2);
1994 iph->ihl = sizeof(struct iphdr) >> 2;
1995 iph->saddr = rt->rt_src;
1996 iph->daddr = rt->rt_dst;
1997 iph->version = 0;
Patrick McHardy0c122952010-04-13 05:03:22 +00001998 err = ipmr_cache_unresolved(mrt, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 read_unlock(&mrt_lock);
2000 return err;
2001 }
2002
2003 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
2004 cache->mfc_flags |= MFC_NOTIFY;
Patrick McHardycb6a4e42010-04-26 16:02:08 +02002005 err = __ipmr_fill_mroute(mrt, skb, cache, rtm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 read_unlock(&mrt_lock);
2007 return err;
2008}
2009
Patrick McHardycb6a4e42010-04-26 16:02:08 +02002010static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
2011 u32 pid, u32 seq, struct mfc_cache *c)
2012{
2013 struct nlmsghdr *nlh;
2014 struct rtmsg *rtm;
2015
2016 nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
2017 if (nlh == NULL)
2018 return -EMSGSIZE;
2019
2020 rtm = nlmsg_data(nlh);
2021 rtm->rtm_family = RTNL_FAMILY_IPMR;
2022 rtm->rtm_dst_len = 32;
2023 rtm->rtm_src_len = 32;
2024 rtm->rtm_tos = 0;
2025 rtm->rtm_table = mrt->id;
2026 NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
2027 rtm->rtm_type = RTN_MULTICAST;
2028 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2029 rtm->rtm_protocol = RTPROT_UNSPEC;
2030 rtm->rtm_flags = 0;
2031
2032 NLA_PUT_BE32(skb, RTA_SRC, c->mfc_origin);
2033 NLA_PUT_BE32(skb, RTA_DST, c->mfc_mcastgrp);
2034
2035 if (__ipmr_fill_mroute(mrt, skb, c, rtm) < 0)
2036 goto nla_put_failure;
2037
2038 return nlmsg_end(skb, nlh);
2039
2040nla_put_failure:
2041 nlmsg_cancel(skb, nlh);
2042 return -EMSGSIZE;
2043}
2044
2045static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
2046{
2047 struct net *net = sock_net(skb->sk);
2048 struct mr_table *mrt;
2049 struct mfc_cache *mfc;
2050 unsigned int t = 0, s_t;
2051 unsigned int h = 0, s_h;
2052 unsigned int e = 0, s_e;
2053
2054 s_t = cb->args[0];
2055 s_h = cb->args[1];
2056 s_e = cb->args[2];
2057
2058 read_lock(&mrt_lock);
2059 ipmr_for_each_table(mrt, net) {
2060 if (t < s_t)
2061 goto next_table;
2062 if (t > s_t)
2063 s_h = 0;
2064 for (h = s_h; h < MFC_LINES; h++) {
2065 list_for_each_entry(mfc, &mrt->mfc_cache_array[h], list) {
2066 if (e < s_e)
2067 goto next_entry;
2068 if (ipmr_fill_mroute(mrt, skb,
2069 NETLINK_CB(cb->skb).pid,
2070 cb->nlh->nlmsg_seq,
2071 mfc) < 0)
2072 goto done;
2073next_entry:
2074 e++;
2075 }
2076 e = s_e = 0;
2077 }
2078 s_h = 0;
2079next_table:
2080 t++;
2081 }
2082done:
2083 read_unlock(&mrt_lock);
2084
2085 cb->args[2] = e;
2086 cb->args[1] = h;
2087 cb->args[0] = t;
2088
2089 return skb->len;
2090}
2091
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002092#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093/*
2094 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
2095 */
2096struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002097 struct seq_net_private p;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002098 struct mr_table *mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 int ct;
2100};
2101
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002102static struct vif_device *ipmr_vif_seq_idx(struct net *net,
2103 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 loff_t pos)
2105{
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002106 struct mr_table *mrt = iter->mrt;
Patrick McHardy0c122952010-04-13 05:03:22 +00002107
2108 for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
2109 if (!VIF_EXISTS(mrt, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002111 if (pos-- == 0)
Patrick McHardy0c122952010-04-13 05:03:22 +00002112 return &mrt->vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 }
2114 return NULL;
2115}
2116
2117static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08002118 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119{
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002120 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002121 struct net *net = seq_file_net(seq);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002122 struct mr_table *mrt;
2123
2124 mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
2125 if (mrt == NULL)
2126 return ERR_PTR(-ENOENT);
2127
2128 iter->mrt = mrt;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002129
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002131 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 : SEQ_START_TOKEN;
2133}
2134
2135static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2136{
2137 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002138 struct net *net = seq_file_net(seq);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002139 struct mr_table *mrt = iter->mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141 ++*pos;
2142 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002143 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002144
Patrick McHardy0c122952010-04-13 05:03:22 +00002145 while (++iter->ct < mrt->maxvif) {
2146 if (!VIF_EXISTS(mrt, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 continue;
Patrick McHardy0c122952010-04-13 05:03:22 +00002148 return &mrt->vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 }
2150 return NULL;
2151}
2152
2153static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08002154 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155{
2156 read_unlock(&mrt_lock);
2157}
2158
2159static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
2160{
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002161 struct ipmr_vif_iter *iter = seq->private;
2162 struct mr_table *mrt = iter->mrt;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002165 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
2167 } else {
2168 const struct vif_device *vif = v;
2169 const char *name = vif->dev ? vif->dev->name : "none";
2170
2171 seq_printf(seq,
2172 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Patrick McHardy0c122952010-04-13 05:03:22 +00002173 vif - mrt->vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002174 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 vif->bytes_out, vif->pkt_out,
2176 vif->flags, vif->local, vif->remote);
2177 }
2178 return 0;
2179}
2180
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002181static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 .start = ipmr_vif_seq_start,
2183 .next = ipmr_vif_seq_next,
2184 .stop = ipmr_vif_seq_stop,
2185 .show = ipmr_vif_seq_show,
2186};
2187
2188static int ipmr_vif_open(struct inode *inode, struct file *file)
2189{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002190 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
2191 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192}
2193
Arjan van de Ven9a321442007-02-12 00:55:35 -08002194static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 .owner = THIS_MODULE,
2196 .open = ipmr_vif_open,
2197 .read = seq_read,
2198 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002199 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200};
2201
2202struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002203 struct seq_net_private p;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002204 struct mr_table *mrt;
Patrick McHardy862465f2010-04-13 05:03:21 +00002205 struct list_head *cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 int ct;
2207};
2208
2209
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002210static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
2211 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002213 struct mr_table *mrt = it->mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 struct mfc_cache *mfc;
2215
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 read_lock(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00002217 for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
Patrick McHardy0c122952010-04-13 05:03:22 +00002218 it->cache = &mrt->mfc_cache_array[it->ct];
Patrick McHardy862465f2010-04-13 05:03:21 +00002219 list_for_each_entry(mfc, it->cache, list)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002220 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return mfc;
Patrick McHardy862465f2010-04-13 05:03:21 +00002222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 read_unlock(&mrt_lock);
2224
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00002226 it->cache = &mrt->mfc_unres_queue;
Patrick McHardy862465f2010-04-13 05:03:21 +00002227 list_for_each_entry(mfc, it->cache, list)
Patrick McHardye258beb2010-04-13 05:03:19 +00002228 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 return mfc;
2230 spin_unlock_bh(&mfc_unres_lock);
2231
2232 it->cache = NULL;
2233 return NULL;
2234}
2235
2236
2237static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
2238{
2239 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002240 struct net *net = seq_file_net(seq);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002241 struct mr_table *mrt;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002242
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002243 mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
2244 if (mrt == NULL)
2245 return ERR_PTR(-ENOENT);
2246
2247 it->mrt = mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 it->cache = NULL;
2249 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002250 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 : SEQ_START_TOKEN;
2252}
2253
2254static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2255{
2256 struct mfc_cache *mfc = v;
2257 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002258 struct net *net = seq_file_net(seq);
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002259 struct mr_table *mrt = it->mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
2261 ++*pos;
2262
2263 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002264 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
Patrick McHardy862465f2010-04-13 05:03:21 +00002266 if (mfc->list.next != it->cache)
2267 return list_entry(mfc->list.next, struct mfc_cache, list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002268
Patrick McHardy0c122952010-04-13 05:03:22 +00002269 if (it->cache == &mrt->mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 goto end_of_list;
2271
Patrick McHardy0c122952010-04-13 05:03:22 +00002272 BUG_ON(it->cache != &mrt->mfc_cache_array[it->ct]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
2274 while (++it->ct < MFC_LINES) {
Patrick McHardy0c122952010-04-13 05:03:22 +00002275 it->cache = &mrt->mfc_cache_array[it->ct];
Patrick McHardy862465f2010-04-13 05:03:21 +00002276 if (list_empty(it->cache))
2277 continue;
2278 return list_first_entry(it->cache, struct mfc_cache, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 }
2280
2281 /* exhausted cache_array, show unresolved */
2282 read_unlock(&mrt_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00002283 it->cache = &mrt->mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00002287 if (!list_empty(it->cache))
2288 return list_first_entry(it->cache, struct mfc_cache, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 end_of_list:
2291 spin_unlock_bh(&mfc_unres_lock);
2292 it->cache = NULL;
2293
2294 return NULL;
2295}
2296
2297static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
2298{
2299 struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002300 struct mr_table *mrt = it->mrt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
Patrick McHardy0c122952010-04-13 05:03:22 +00002302 if (it->cache == &mrt->mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 spin_unlock_bh(&mfc_unres_lock);
Patrick McHardy0c122952010-04-13 05:03:22 +00002304 else if (it->cache == &mrt->mfc_cache_array[it->ct])
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 read_unlock(&mrt_lock);
2306}
2307
2308static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
2309{
2310 int n;
2311
2312 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002313 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
2315 } else {
2316 const struct mfc_cache *mfc = v;
2317 const struct ipmr_mfc_iter *it = seq->private;
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002318 const struct mr_table *mrt = it->mrt;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002319
Eric Dumazet0eae88f2010-04-20 19:06:52 -07002320 seq_printf(seq, "%08X %08X %-3hd",
2321 (__force u32) mfc->mfc_mcastgrp,
2322 (__force u32) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08002323 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
Patrick McHardy0c122952010-04-13 05:03:22 +00002325 if (it->cache != &mrt->mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08002326 seq_printf(seq, " %8lu %8lu %8lu",
2327 mfc->mfc_un.res.pkt,
2328 mfc->mfc_un.res.bytes,
2329 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08002330 for (n = mfc->mfc_un.res.minvif;
2331 n < mfc->mfc_un.res.maxvif; n++ ) {
Patrick McHardy0c122952010-04-13 05:03:22 +00002332 if (VIF_EXISTS(mrt, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00002333 mfc->mfc_un.res.ttls[n] < 255)
2334 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002335 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 n, mfc->mfc_un.res.ttls[n]);
2337 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08002338 } else {
2339 /* unresolved mfc_caches don't contain
2340 * pkt, bytes and wrong_if values
2341 */
2342 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 }
2344 seq_putc(seq, '\n');
2345 }
2346 return 0;
2347}
2348
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002349static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 .start = ipmr_mfc_seq_start,
2351 .next = ipmr_mfc_seq_next,
2352 .stop = ipmr_mfc_seq_stop,
2353 .show = ipmr_mfc_seq_show,
2354};
2355
2356static int ipmr_mfc_open(struct inode *inode, struct file *file)
2357{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002358 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
2359 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360}
2361
Arjan van de Ven9a321442007-02-12 00:55:35 -08002362static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 .owner = THIS_MODULE,
2364 .open = ipmr_mfc_open,
2365 .read = seq_read,
2366 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002367 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002369#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
2371#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00002372static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07002374 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375};
2376#endif
2377
2378
2379/*
2380 * Setup for IP multicast routing
2381 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00002382static int __net_init ipmr_net_init(struct net *net)
2383{
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002384 int err;
Benjamin Therycf958ae32009-01-22 04:56:16 +00002385
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002386 err = ipmr_rules_init(net);
2387 if (err < 0)
Benjamin Therycf958ae32009-01-22 04:56:16 +00002388 goto fail;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002389
2390#ifdef CONFIG_PROC_FS
2391 err = -ENOMEM;
2392 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
2393 goto proc_vif_fail;
2394 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
2395 goto proc_cache_fail;
2396#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002397 return 0;
2398
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002399#ifdef CONFIG_PROC_FS
2400proc_cache_fail:
2401 proc_net_remove(net, "ip_mr_vif");
2402proc_vif_fail:
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002403 ipmr_rules_exit(net);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002404#endif
Benjamin Therycf958ae32009-01-22 04:56:16 +00002405fail:
2406 return err;
2407}
2408
2409static void __net_exit ipmr_net_exit(struct net *net)
2410{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002411#ifdef CONFIG_PROC_FS
2412 proc_net_remove(net, "ip_mr_cache");
2413 proc_net_remove(net, "ip_mr_vif");
2414#endif
Patrick McHardyf0ad0862010-04-13 05:03:23 +00002415 ipmr_rules_exit(net);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002416}
2417
2418static struct pernet_operations ipmr_net_ops = {
2419 .init = ipmr_net_init,
2420 .exit = ipmr_net_exit,
2421};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002422
Wang Chen03d2f892008-07-03 12:13:36 +08002423int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424{
Wang Chen03d2f892008-07-03 12:13:36 +08002425 int err;
2426
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2428 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002429 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002430 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002431 if (!mrt_cachep)
2432 return -ENOMEM;
2433
Benjamin Therycf958ae32009-01-22 04:56:16 +00002434 err = register_pernet_subsys(&ipmr_net_ops);
2435 if (err)
2436 goto reg_pernet_fail;
2437
Wang Chen03d2f892008-07-03 12:13:36 +08002438 err = register_netdevice_notifier(&ip_mr_notifier);
2439 if (err)
2440 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002441#ifdef CONFIG_IP_PIMSM_V2
2442 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2443 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2444 err = -EAGAIN;
2445 goto add_proto_fail;
2446 }
2447#endif
Patrick McHardycb6a4e42010-04-26 16:02:08 +02002448 rtnl_register(RTNL_FAMILY_IPMR, RTM_GETROUTE, NULL, ipmr_rtm_dumproute);
Wang Chen03d2f892008-07-03 12:13:36 +08002449 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002450
Tom Goff403dbb92009-06-14 03:16:13 -07002451#ifdef CONFIG_IP_PIMSM_V2
2452add_proto_fail:
2453 unregister_netdevice_notifier(&ip_mr_notifier);
2454#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002455reg_notif_fail:
Benjamin Therycf958ae32009-01-22 04:56:16 +00002456 unregister_pernet_subsys(&ipmr_net_ops);
2457reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002458 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002459 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460}