blob: 9d4f6d1340a438b2f8004d3906b52e6bfe069756 [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
25 * Relax this requrement to work with older peers.
26 *
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
68#define CONFIG_IP_PIMSM 1
69#endif
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* Big lock, protecting vif table, mrt cache and mroute socket state.
72 Note that the changes are semaphored via rtnl_lock.
73 */
74
75static DEFINE_RWLOCK(mrt_lock);
76
77/*
78 * Multicast router control variables
79 */
80
Benjamin Therycf958ae32009-01-22 04:56:16 +000081#define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Special spinlock for queue of unresolved entries */
86static DEFINE_SPINLOCK(mfc_unres_lock);
87
88/* We return to original Alan's scheme. Hash table of resolved
89 entries is changed only in process context and protected
90 with weak lock mrt_lock. Queue of unresolved entries is protected
91 with strong spinlock mfc_unres_lock.
92
93 In this case data path is free of exclusive locks at all.
94 */
95
Christoph Lametere18b8902006-12-06 20:33:20 -080096static struct kmem_cache *mrt_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
Benjamin Thery4feb88e2009-01-22 04:56:23 +000099static int ipmr_cache_report(struct net *net,
100 struct sk_buff *pkt, vifi_t vifi, int assert);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static struct timer_list ipmr_expire_timer;
104
105/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
106
Wang Chend6070322008-07-14 20:55:26 -0700107static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
108{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000109 struct net *net = dev_net(dev);
110
Wang Chend6070322008-07-14 20:55:26 -0700111 dev_close(dev);
112
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000113 dev = __dev_get_by_name(net, "tunl0");
Wang Chend6070322008-07-14 20:55:26 -0700114 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800115 const struct net_device_ops *ops = dev->netdev_ops;
Wang Chend6070322008-07-14 20:55:26 -0700116 struct ifreq ifr;
Wang Chend6070322008-07-14 20:55:26 -0700117 struct ip_tunnel_parm p;
118
119 memset(&p, 0, sizeof(p));
120 p.iph.daddr = v->vifc_rmt_addr.s_addr;
121 p.iph.saddr = v->vifc_lcl_addr.s_addr;
122 p.iph.version = 4;
123 p.iph.ihl = 5;
124 p.iph.protocol = IPPROTO_IPIP;
125 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
126 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
127
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800128 if (ops->ndo_do_ioctl) {
129 mm_segment_t oldfs = get_fs();
130
131 set_fs(KERNEL_DS);
132 ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
133 set_fs(oldfs);
134 }
Wang Chend6070322008-07-14 20:55:26 -0700135 }
136}
137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000139struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
141 struct net_device *dev;
142
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000143 dev = __dev_get_by_name(net, "tunl0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800146 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 int err;
148 struct ifreq ifr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 struct ip_tunnel_parm p;
150 struct in_device *in_dev;
151
152 memset(&p, 0, sizeof(p));
153 p.iph.daddr = v->vifc_rmt_addr.s_addr;
154 p.iph.saddr = v->vifc_lcl_addr.s_addr;
155 p.iph.version = 4;
156 p.iph.ihl = 5;
157 p.iph.protocol = IPPROTO_IPIP;
158 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
Stephen Hemmingerba93ef72008-01-21 17:28:59 -0800159 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800161 if (ops->ndo_do_ioctl) {
162 mm_segment_t oldfs = get_fs();
163
164 set_fs(KERNEL_DS);
165 err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
166 set_fs(oldfs);
167 } else
168 err = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170 dev = NULL;
171
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000172 if (err == 0 &&
173 (dev = __dev_get_by_name(net, p.name)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 dev->flags |= IFF_MULTICAST;
175
Herbert Xue5ed6392005-10-03 14:35:55 -0700176 in_dev = __in_dev_get_rtnl(dev);
Herbert Xu71e27da2007-06-04 23:36:06 -0700177 if (in_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700179
180 ipv4_devconf_setall(in_dev);
181 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 if (dev_open(dev))
184 goto failure;
Wang Chen7dc00c82008-07-14 20:56:34 -0700185 dev_hold(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 }
187 }
188 return dev;
189
190failure:
191 /* allow the register to be completed before unregistering. */
192 rtnl_unlock();
193 rtnl_lock();
194
195 unregister_netdevice(dev);
196 return NULL;
197}
198
199#ifdef CONFIG_IP_PIMSM
200
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000201static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000203 struct net *net = dev_net(dev);
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 read_lock(&mrt_lock);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700206 dev->stats.tx_bytes += skb->len;
207 dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000208 ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
209 IGMPMSG_WHOLEPKT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 read_unlock(&mrt_lock);
211 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000212 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Stephen Hemminger007c3832008-11-20 20:28:35 -0800215static const struct net_device_ops reg_vif_netdev_ops = {
216 .ndo_start_xmit = reg_vif_xmit,
217};
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219static void reg_vif_setup(struct net_device *dev)
220{
221 dev->type = ARPHRD_PIMREG;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800222 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800224 dev->netdev_ops = &reg_vif_netdev_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700226 dev->features |= NETIF_F_NETNS_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
Tom Goff403dbb92009-06-14 03:16:13 -0700229static struct net_device *ipmr_reg_vif(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 struct net_device *dev;
232 struct in_device *in_dev;
233
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700234 dev = alloc_netdev(0, "pimreg", reg_vif_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236 if (dev == NULL)
237 return NULL;
238
Tom Goff403dbb92009-06-14 03:16:13 -0700239 dev_net_set(dev, net);
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (register_netdevice(dev)) {
242 free_netdev(dev);
243 return NULL;
244 }
245 dev->iflink = 0;
246
Herbert Xu71e27da2007-06-04 23:36:06 -0700247 rcu_read_lock();
248 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
249 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Herbert Xu71e27da2007-06-04 23:36:06 -0700253 ipv4_devconf_setall(in_dev);
254 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
255 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if (dev_open(dev))
258 goto failure;
259
Wang Chen7dc00c82008-07-14 20:56:34 -0700260 dev_hold(dev);
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return dev;
263
264failure:
265 /* allow the register to be completed before unregistering. */
266 rtnl_unlock();
267 rtnl_lock();
268
269 unregister_netdevice(dev);
270 return NULL;
271}
272#endif
273
274/*
275 * Delete a VIF entry
Wang Chen7dc00c82008-07-14 20:56:34 -0700276 * @notify: Set to 1, if the caller is a notifier_call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900278
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000279static int vif_delete(struct net *net, int vifi, int notify,
280 struct list_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 struct vif_device *v;
283 struct net_device *dev;
284 struct in_device *in_dev;
285
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000286 if (vifi < 0 || vifi >= net->ipv4.maxvif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return -EADDRNOTAVAIL;
288
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000289 v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 write_lock_bh(&mrt_lock);
292 dev = v->dev;
293 v->dev = NULL;
294
295 if (!dev) {
296 write_unlock_bh(&mrt_lock);
297 return -EADDRNOTAVAIL;
298 }
299
300#ifdef CONFIG_IP_PIMSM
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000301 if (vifi == net->ipv4.mroute_reg_vif_num)
302 net->ipv4.mroute_reg_vif_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303#endif
304
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000305 if (vifi+1 == net->ipv4.maxvif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 int tmp;
307 for (tmp=vifi-1; tmp>=0; tmp--) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000308 if (VIF_EXISTS(net, tmp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 break;
310 }
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000311 net->ipv4.maxvif = tmp+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
313
314 write_unlock_bh(&mrt_lock);
315
316 dev_set_allmulti(dev, -1);
317
Herbert Xue5ed6392005-10-03 14:35:55 -0700318 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Herbert Xu42f811b2007-06-04 23:34:44 -0700319 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 ip_rt_multicast_event(in_dev);
321 }
322
Wang Chen7dc00c82008-07-14 20:56:34 -0700323 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000324 unregister_netdevice_queue(dev, head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 dev_put(dev);
327 return 0;
328}
329
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000330static inline void ipmr_cache_free(struct mfc_cache *c)
331{
332 release_net(mfc_net(c));
333 kmem_cache_free(mrt_cachep, c);
334}
335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336/* Destroy an unresolved cache entry, killing queued skbs
337 and reporting error to netlink readers.
338 */
339
340static void ipmr_destroy_unres(struct mfc_cache *c)
341{
342 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700343 struct nlmsgerr *e;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000344 struct net *net = mfc_net(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000346 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Jianjun Kongc354e122008-11-03 00:28:02 -0800348 while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700349 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
351 nlh->nlmsg_type = NLMSG_ERROR;
352 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
353 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700354 e = NLMSG_DATA(nlh);
355 e->error = -ETIMEDOUT;
356 memset(&e->msg, 0, sizeof(e->msg));
Thomas Graf2942e902006-08-15 00:30:25 -0700357
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000358 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 } else
360 kfree_skb(skb);
361 }
362
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000363 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
366
367/* Single timer process for all the unresolved queue. */
368
369static void ipmr_expire_process(unsigned long dummy)
370{
371 unsigned long now;
372 unsigned long expires;
373 struct mfc_cache *c, **cp;
374
375 if (!spin_trylock(&mfc_unres_lock)) {
376 mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
377 return;
378 }
379
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000380 if (mfc_unres_queue == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 goto out;
382
383 now = jiffies;
384 expires = 10*HZ;
385 cp = &mfc_unres_queue;
386
387 while ((c=*cp) != NULL) {
388 if (time_after(c->mfc_un.unres.expires, now)) {
389 unsigned long interval = c->mfc_un.unres.expires - now;
390 if (interval < expires)
391 expires = interval;
392 cp = &c->next;
393 continue;
394 }
395
396 *cp = c->next;
397
398 ipmr_destroy_unres(c);
399 }
400
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000401 if (mfc_unres_queue != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 mod_timer(&ipmr_expire_timer, jiffies + expires);
403
404out:
405 spin_unlock(&mfc_unres_lock);
406}
407
408/* Fill oifs list. It is called under write locked mrt_lock. */
409
Baruch Evend1b04c02005-07-30 17:41:59 -0700410static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 int vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000413 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 cache->mfc_un.res.minvif = MAXVIFS;
416 cache->mfc_un.res.maxvif = 0;
417 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
418
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000419 for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
420 if (VIF_EXISTS(net, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000421 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
423 if (cache->mfc_un.res.minvif > vifi)
424 cache->mfc_un.res.minvif = vifi;
425 if (cache->mfc_un.res.maxvif <= vifi)
426 cache->mfc_un.res.maxvif = vifi + 1;
427 }
428 }
429}
430
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000431static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 int vifi = vifc->vifc_vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000434 struct vif_device *v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 struct net_device *dev;
436 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700437 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439 /* Is vif busy ? */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000440 if (VIF_EXISTS(net, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 return -EADDRINUSE;
442
443 switch (vifc->vifc_flags) {
444#ifdef CONFIG_IP_PIMSM
445 case VIFF_REGISTER:
446 /*
447 * Special Purpose VIF in PIM
448 * All the packets will be sent to the daemon
449 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000450 if (net->ipv4.mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return -EADDRINUSE;
Tom Goff403dbb92009-06-14 03:16:13 -0700452 dev = ipmr_reg_vif(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (!dev)
454 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700455 err = dev_set_allmulti(dev, 1);
456 if (err) {
457 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700458 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700459 return err;
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
462#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900463 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000464 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (!dev)
466 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700467 err = dev_set_allmulti(dev, 1);
468 if (err) {
469 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700470 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700471 return err;
472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 break;
Ilia Kee5e81f2009-09-16 05:53:07 +0000474
475 case VIFF_USE_IFINDEX:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 case 0:
Ilia Kee5e81f2009-09-16 05:53:07 +0000477 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
478 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
479 if (dev && dev->ip_ptr == NULL) {
480 dev_put(dev);
481 return -EADDRNOTAVAIL;
482 }
483 } else
484 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (!dev)
487 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700488 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700489 if (err) {
490 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700491 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 break;
494 default:
495 return -EINVAL;
496 }
497
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000498 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
499 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000501 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700502 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 ip_rt_multicast_event(in_dev);
504
505 /*
506 * Fill in the VIF structures
507 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800508 v->rate_limit = vifc->vifc_rate_limit;
509 v->local = vifc->vifc_lcl_addr.s_addr;
510 v->remote = vifc->vifc_rmt_addr.s_addr;
511 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!mrtsock)
513 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800514 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 v->bytes_in = 0;
516 v->bytes_out = 0;
517 v->pkt_in = 0;
518 v->pkt_out = 0;
519 v->link = dev->ifindex;
520 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
521 v->link = dev->iflink;
522
523 /* And finish update writing critical data */
524 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800525 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526#ifdef CONFIG_IP_PIMSM
527 if (v->flags&VIFF_REGISTER)
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000528 net->ipv4.mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529#endif
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000530 if (vifi+1 > net->ipv4.maxvif)
531 net->ipv4.maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 write_unlock_bh(&mrt_lock);
533 return 0;
534}
535
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000536static struct mfc_cache *ipmr_cache_find(struct net *net,
537 __be32 origin,
538 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
Jianjun Kongc354e122008-11-03 00:28:02 -0800540 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 struct mfc_cache *c;
542
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000543 for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
545 break;
546 }
547 return c;
548}
549
550/*
551 * Allocate a multicast cache entry
552 */
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000553static struct mfc_cache *ipmr_cache_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Jianjun Kongc354e122008-11-03 00:28:02 -0800555 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
556 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 c->mfc_un.res.minvif = MAXVIFS;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000559 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return c;
561}
562
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000563static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
Jianjun Kongc354e122008-11-03 00:28:02 -0800565 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
566 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 skb_queue_head_init(&c->mfc_un.unres.unresolved);
569 c->mfc_un.unres.expires = jiffies + 10*HZ;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000570 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return c;
572}
573
574/*
575 * A cache entry has gone into a resolved state from queued
576 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
579{
580 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700581 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583 /*
584 * Play the pending entries through our router
585 */
586
Jianjun Kongc354e122008-11-03 00:28:02 -0800587 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700588 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
590
591 if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700592 nlh->nlmsg_len = (skb_tail_pointer(skb) -
593 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 } else {
595 nlh->nlmsg_type = NLMSG_ERROR;
596 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
597 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700598 e = NLMSG_DATA(nlh);
599 e->error = -EMSGSIZE;
600 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
Thomas Graf2942e902006-08-15 00:30:25 -0700602
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000603 rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else
605 ip_mr_forward(skb, c, 0);
606 }
607}
608
609/*
610 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
611 * expects the following bizarre scheme.
612 *
613 * Called under mrt_lock.
614 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900615
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000616static int ipmr_cache_report(struct net *net,
617 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300620 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 struct igmphdr *igmp;
622 struct igmpmsg *msg;
623 int ret;
624
625#ifdef CONFIG_IP_PIMSM
626 if (assert == IGMPMSG_WHOLEPKT)
627 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
628 else
629#endif
630 skb = alloc_skb(128, GFP_ATOMIC);
631
Stephen Hemminger132adf52007-03-08 20:44:43 -0800632 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return -ENOBUFS;
634
635#ifdef CONFIG_IP_PIMSM
636 if (assert == IGMPMSG_WHOLEPKT) {
637 /* Ugly, but we have no choice with this interface.
638 Duplicate old header, fix ihl, length etc.
639 And all this only to mangle msg->im_msgtype and
640 to set msg->im_mbz to "mbz" :-)
641 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300642 skb_push(skb, sizeof(struct iphdr));
643 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300644 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300645 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700646 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 msg->im_msgtype = IGMPMSG_WHOLEPKT;
648 msg->im_mbz = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000649 msg->im_vif = net->ipv4.mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700650 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
651 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
652 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900653 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900655 {
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /*
658 * Copy the IP header
659 */
660
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700661 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300662 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300663 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700664 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
665 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000667 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 /*
670 * Add our header
671 */
672
Jianjun Kongc354e122008-11-03 00:28:02 -0800673 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 igmp->type =
675 msg->im_msgtype = assert;
676 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700677 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700678 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000681 if (net->ipv4.mroute_sk == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 kfree_skb(skb);
683 return -EINVAL;
684 }
685
686 /*
687 * Deliver to mrouted
688 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000689 ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
Benjamin Thery70a269e2009-01-22 04:56:15 +0000690 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 if (net_ratelimit())
692 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
693 kfree_skb(skb);
694 }
695
696 return ret;
697}
698
699/*
700 * Queue a packet for resolution. It gets locked cache entry!
701 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703static int
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000704ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 int err;
707 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700708 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 spin_lock_bh(&mfc_unres_lock);
711 for (c=mfc_unres_queue; c; c=c->next) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000712 if (net_eq(mfc_net(c), net) &&
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000713 c->mfc_mcastgrp == iph->daddr &&
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700714 c->mfc_origin == iph->saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 break;
716 }
717
718 if (c == NULL) {
719 /*
720 * Create a new entry if allowable
721 */
722
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000723 if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
724 (c = ipmr_cache_alloc_unres(net)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 spin_unlock_bh(&mfc_unres_lock);
726
727 kfree_skb(skb);
728 return -ENOBUFS;
729 }
730
731 /*
732 * Fill in the new cache entry
733 */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700734 c->mfc_parent = -1;
735 c->mfc_origin = iph->saddr;
736 c->mfc_mcastgrp = iph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 /*
739 * Reflect first query at mrouted.
740 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000741 err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
742 if (err < 0) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900743 /* If the report failed throw the cache entry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 out - Brad Parker
745 */
746 spin_unlock_bh(&mfc_unres_lock);
747
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000748 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 kfree_skb(skb);
750 return err;
751 }
752
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000753 atomic_inc(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 c->next = mfc_unres_queue;
755 mfc_unres_queue = c;
756
757 mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
758 }
759
760 /*
761 * See if we can append the packet
762 */
763 if (c->mfc_un.unres.unresolved.qlen>3) {
764 kfree_skb(skb);
765 err = -ENOBUFS;
766 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800767 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 err = 0;
769 }
770
771 spin_unlock_bh(&mfc_unres_lock);
772 return err;
773}
774
775/*
776 * MFC cache manipulation by user space mroute daemon
777 */
778
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000779static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 int line;
782 struct mfc_cache *c, **cp;
783
Jianjun Kongc354e122008-11-03 00:28:02 -0800784 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000786 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000787 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
789 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
790 write_lock_bh(&mrt_lock);
791 *cp = c->next;
792 write_unlock_bh(&mrt_lock);
793
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000794 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return 0;
796 }
797 }
798 return -ENOENT;
799}
800
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000801static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 int line;
804 struct mfc_cache *uc, *c, **cp;
805
Patrick McHardya50436f22010-03-17 06:04:14 +0000806 if (mfc->mfcc_parent >= MAXVIFS)
807 return -ENFILE;
808
Jianjun Kongc354e122008-11-03 00:28:02 -0800809 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000811 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000812 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
814 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
815 break;
816 }
817
818 if (c != NULL) {
819 write_lock_bh(&mrt_lock);
820 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700821 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (!mrtsock)
823 c->mfc_flags |= MFC_STATIC;
824 write_unlock_bh(&mrt_lock);
825 return 0;
826 }
827
Joe Perchesf97c1e02007-12-16 13:45:43 -0800828 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return -EINVAL;
830
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000831 c = ipmr_cache_alloc(net);
Jianjun Kongc354e122008-11-03 00:28:02 -0800832 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 return -ENOMEM;
834
Jianjun Kongc354e122008-11-03 00:28:02 -0800835 c->mfc_origin = mfc->mfcc_origin.s_addr;
836 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
837 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700838 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (!mrtsock)
840 c->mfc_flags |= MFC_STATIC;
841
842 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000843 c->next = net->ipv4.mfc_cache_array[line];
844 net->ipv4.mfc_cache_array[line] = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 write_unlock_bh(&mrt_lock);
846
847 /*
848 * Check to see if we resolved a queued list. If so we
849 * need to send on the frames and tidy up.
850 */
851 spin_lock_bh(&mfc_unres_lock);
852 for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
853 cp = &uc->next) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000854 if (net_eq(mfc_net(uc), net) &&
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000855 uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
857 *cp = uc->next;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000858 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 break;
860 }
861 }
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000862 if (mfc_unres_queue == NULL)
863 del_timer(&ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 spin_unlock_bh(&mfc_unres_lock);
865
866 if (uc) {
867 ipmr_cache_resolve(uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000868 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 }
870 return 0;
871}
872
873/*
874 * Close the multicast socket, and clear the vif tables etc
875 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900876
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000877static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
879 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000880 LIST_HEAD(list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 /*
883 * Shut down all active vif entries
884 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000885 for (i = 0; i < net->ipv4.maxvif; i++) {
886 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000887 vif_delete(net, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000889 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 /*
892 * Wipe the cache
893 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800894 for (i=0; i<MFC_LINES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 struct mfc_cache *c, **cp;
896
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000897 cp = &net->ipv4.mfc_cache_array[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 while ((c = *cp) != NULL) {
899 if (c->mfc_flags&MFC_STATIC) {
900 cp = &c->next;
901 continue;
902 }
903 write_lock_bh(&mrt_lock);
904 *cp = c->next;
905 write_unlock_bh(&mrt_lock);
906
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000907 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 }
910
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000911 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000912 struct mfc_cache *c, **cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 spin_lock_bh(&mfc_unres_lock);
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000915 cp = &mfc_unres_queue;
916 while ((c = *cp) != NULL) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000917 if (!net_eq(mfc_net(c), net)) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000918 cp = &c->next;
919 continue;
920 }
921 *cp = c->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 ipmr_destroy_unres(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 }
925 spin_unlock_bh(&mfc_unres_lock);
926 }
927}
928
929static void mrtsock_destruct(struct sock *sk)
930{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000931 struct net *net = sock_net(sk);
932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000934 if (sk == net->ipv4.mroute_sk) {
935 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000938 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 write_unlock_bh(&mrt_lock);
940
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000941 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
943 rtnl_unlock();
944}
945
946/*
947 * Socket options and virtual interface manipulation. The whole
948 * virtual interface system is a complete heap, but unfortunately
949 * that's how BSD mrouted happens to think. Maybe one day with a proper
950 * MOSPF/PIM router set up we can clean this up.
951 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900952
David S. Millerb7058842009-09-30 16:12:20 -0700953int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
955 int ret;
956 struct vifctl vif;
957 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000958 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900959
Stephen Hemminger132adf52007-03-08 20:44:43 -0800960 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000961 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return -EACCES;
963 }
964
Stephen Hemminger132adf52007-03-08 20:44:43 -0800965 switch (optname) {
966 case MRT_INIT:
967 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000968 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800969 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800970 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800971 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Stephen Hemminger132adf52007-03-08 20:44:43 -0800973 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000974 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800976 return -EADDRINUSE;
977 }
978
979 ret = ip_ra_control(sk, 1, mrtsock_destruct);
980 if (ret == 0) {
981 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000982 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800983 write_unlock_bh(&mrt_lock);
984
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000985 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800986 }
987 rtnl_unlock();
988 return ret;
989 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000990 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800991 return -EACCES;
992 return ip_ra_control(sk, 0, NULL);
993 case MRT_ADD_VIF:
994 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800995 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800996 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800997 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800998 return -EFAULT;
999 if (vif.vifc_vifi >= MAXVIFS)
1000 return -ENFILE;
1001 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001002 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001003 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001004 } else {
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001005 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001006 }
1007 rtnl_unlock();
1008 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010 /*
1011 * Manipulate the forwarding caches. These live
1012 * in a sort of kernel/user symbiosis.
1013 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001014 case MRT_ADD_MFC:
1015 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -08001016 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001017 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001018 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001019 return -EFAULT;
1020 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001021 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001022 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001023 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001024 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001025 rtnl_unlock();
1026 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 /*
1028 * Control PIM assert.
1029 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001030 case MRT_ASSERT:
1031 {
1032 int v;
1033 if (get_user(v,(int __user *)optval))
1034 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001035 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001036 return 0;
1037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001039 case MRT_PIM:
1040 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001041 int v;
1042
Stephen Hemminger132adf52007-03-08 20:44:43 -08001043 if (get_user(v,(int __user *)optval))
1044 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001045 v = (v) ? 1 : 0;
1046
Stephen Hemminger132adf52007-03-08 20:44:43 -08001047 rtnl_lock();
1048 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001049 if (v != net->ipv4.mroute_do_pim) {
1050 net->ipv4.mroute_do_pim = v;
1051 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001053 rtnl_unlock();
1054 return ret;
1055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001057 /*
1058 * Spurious command, or MRT_VERSION which you cannot
1059 * set.
1060 */
1061 default:
1062 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064}
1065
1066/*
1067 * Getsock opt support for the multicast routing system.
1068 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001069
Jianjun Kongc354e122008-11-03 00:28:02 -08001070int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
1072 int olr;
1073 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001074 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Jianjun Kongc354e122008-11-03 00:28:02 -08001076 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077#ifdef CONFIG_IP_PIMSM
1078 optname!=MRT_PIM &&
1079#endif
1080 optname!=MRT_ASSERT)
1081 return -ENOPROTOOPT;
1082
1083 if (get_user(olr, optlen))
1084 return -EFAULT;
1085
1086 olr = min_t(unsigned int, olr, sizeof(int));
1087 if (olr < 0)
1088 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001089
Jianjun Kongc354e122008-11-03 00:28:02 -08001090 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001092 if (optname == MRT_VERSION)
1093 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001095 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001096 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097#endif
1098 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001099 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001100 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return -EFAULT;
1102 return 0;
1103}
1104
1105/*
1106 * The IP multicast ioctl support routines.
1107 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1110{
1111 struct sioc_sg_req sr;
1112 struct sioc_vif_req vr;
1113 struct vif_device *vif;
1114 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001115 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001116
Stephen Hemminger132adf52007-03-08 20:44:43 -08001117 switch (cmd) {
1118 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001119 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001120 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001121 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001122 return -EINVAL;
1123 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001124 vif = &net->ipv4.vif_table[vr.vifi];
1125 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001126 vr.icount = vif->pkt_in;
1127 vr.ocount = vif->pkt_out;
1128 vr.ibytes = vif->bytes_in;
1129 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001131
Jianjun Kongc354e122008-11-03 00:28:02 -08001132 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001134 return 0;
1135 }
1136 read_unlock(&mrt_lock);
1137 return -EADDRNOTAVAIL;
1138 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001139 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001140 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Stephen Hemminger132adf52007-03-08 20:44:43 -08001142 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001143 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001144 if (c) {
1145 sr.pktcnt = c->mfc_un.res.pkt;
1146 sr.bytecnt = c->mfc_un.res.bytes;
1147 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001149
Jianjun Kongc354e122008-11-03 00:28:02 -08001150 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001151 return -EFAULT;
1152 return 0;
1153 }
1154 read_unlock(&mrt_lock);
1155 return -EADDRNOTAVAIL;
1156 default:
1157 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
1159}
1160
1161
1162static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1163{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001164 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001165 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 struct vif_device *v;
1167 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001168 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (event != NETDEV_UNREGISTER)
1171 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001172 v = &net->ipv4.vif_table[0];
1173 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001174 if (v->dev == dev)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001175 vif_delete(net, ct, 1, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001177 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return NOTIFY_DONE;
1179}
1180
1181
Jianjun Kongc354e122008-11-03 00:28:02 -08001182static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 .notifier_call = ipmr_device_event,
1184};
1185
1186/*
1187 * Encapsulate a packet by attaching a valid IPIP header to it.
1188 * This avoids tunnel drivers and other mess and gives us the speed so
1189 * important for multicast video.
1190 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001191
Al Viro114c7842006-09-27 18:39:29 -07001192static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001194 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001195 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001196
1197 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001198 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001199 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001200 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001203 iph->tos = old_iph->tos;
1204 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 iph->frag_off = 0;
1206 iph->daddr = daddr;
1207 iph->saddr = saddr;
1208 iph->protocol = IPPROTO_IPIP;
1209 iph->ihl = 5;
1210 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001211 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 ip_send_check(iph);
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1215 nf_reset(skb);
1216}
1217
1218static inline int ipmr_forward_finish(struct sk_buff *skb)
1219{
1220 struct ip_options * opt = &(IPCB(skb)->opt);
1221
Eric Dumazetadf30902009-06-02 05:19:30 +00001222 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 if (unlikely(opt->optlen))
1225 ip_forward_options(skb);
1226
1227 return dst_output(skb);
1228}
1229
1230/*
1231 * Processing handlers for ipmr_forward
1232 */
1233
1234static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
1235{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001236 struct net *net = mfc_net(c);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001237 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001238 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 struct net_device *dev;
1240 struct rtable *rt;
1241 int encap = 0;
1242
1243 if (vif->dev == NULL)
1244 goto out_free;
1245
1246#ifdef CONFIG_IP_PIMSM
1247 if (vif->flags & VIFF_REGISTER) {
1248 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001249 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001250 vif->dev->stats.tx_bytes += skb->len;
1251 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001252 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001253 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
1255#endif
1256
1257 if (vif->flags&VIFF_TUNNEL) {
1258 struct flowi fl = { .oif = vif->link,
1259 .nl_u = { .ip4_u =
1260 { .daddr = vif->remote,
1261 .saddr = vif->local,
1262 .tos = RT_TOS(iph->tos) } },
1263 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001264 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 goto out_free;
1266 encap = sizeof(struct iphdr);
1267 } else {
1268 struct flowi fl = { .oif = vif->link,
1269 .nl_u = { .ip4_u =
1270 { .daddr = iph->daddr,
1271 .tos = RT_TOS(iph->tos) } },
1272 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001273 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 goto out_free;
1275 }
1276
1277 dev = rt->u.dst.dev;
1278
1279 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1280 /* Do not fragment multicasts. Alas, IPv4 does not
1281 allow to send ICMP, so that packets will disappear
1282 to blackhole.
1283 */
1284
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001285 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 ip_rt_put(rt);
1287 goto out_free;
1288 }
1289
1290 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1291
1292 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001293 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 goto out_free;
1295 }
1296
1297 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001298 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Eric Dumazetadf30902009-06-02 05:19:30 +00001300 skb_dst_drop(skb);
1301 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001302 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304 /* FIXME: forward and output firewalls used to be called here.
1305 * What do we do with netfilter? -- RR */
1306 if (vif->flags & VIFF_TUNNEL) {
1307 ip_encap(skb, vif->local, vif->remote);
1308 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001309 vif->dev->stats.tx_packets++;
1310 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 }
1312
1313 IPCB(skb)->flags |= IPSKB_FORWARDED;
1314
1315 /*
1316 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1317 * not only before forwarding, but after forwarding on all output
1318 * interfaces. It is clear, if mrouter runs a multicasting
1319 * program, it should receive packets not depending to what interface
1320 * program is joined.
1321 * If we will not make it, the program will have to join on all
1322 * interfaces. On the other hand, multihoming host (or router, but
1323 * not mrouter) cannot join to more than one interface - it will
1324 * result in receiving multiple packets.
1325 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001326 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 ipmr_forward_finish);
1328 return;
1329
1330out_free:
1331 kfree_skb(skb);
1332 return;
1333}
1334
1335static int ipmr_find_vif(struct net_device *dev)
1336{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001337 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001339 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1340 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 break;
1342 }
1343 return ct;
1344}
1345
1346/* "local" means that we should preserve one skb (for local delivery) */
1347
1348static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
1349{
1350 int psend = -1;
1351 int vif, ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001352 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354 vif = cache->mfc_parent;
1355 cache->mfc_un.res.pkt++;
1356 cache->mfc_un.res.bytes += skb->len;
1357
1358 /*
1359 * Wrong interface: drop packet and (maybe) send PIM assert.
1360 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001361 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 int true_vifi;
1363
Eric Dumazet511c3f92009-06-02 05:14:27 +00001364 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 /* It is our own packet, looped back.
1366 Very complicated situation...
1367
1368 The best workaround until routing daemons will be
1369 fixed is not to redistribute packet, if it was
1370 send through wrong interface. It means, that
1371 multicast applications WILL NOT work for
1372 (S,G), which have default multicast route pointing
1373 to wrong oif. In any case, it is not a good
1374 idea to use multicasting applications on router.
1375 */
1376 goto dont_forward;
1377 }
1378
1379 cache->mfc_un.res.wrong_if++;
1380 true_vifi = ipmr_find_vif(skb->dev);
1381
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001382 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 /* pimsm uses asserts, when switching from RPT to SPT,
1384 so that we cannot check that packet arrived on an oif.
1385 It is bad, but otherwise we would need to move pretty
1386 large chunk of pimd to kernel. Ough... --ANK
1387 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001388 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001389 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001390 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1392 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001393 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 }
1395 goto dont_forward;
1396 }
1397
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001398 net->ipv4.vif_table[vif].pkt_in++;
1399 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 /*
1402 * Forward the frame
1403 */
1404 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001405 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (psend != -1) {
1407 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1408 if (skb2)
1409 ipmr_queue_xmit(skb2, cache, psend);
1410 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001411 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413 }
1414 if (psend != -1) {
1415 if (local) {
1416 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1417 if (skb2)
1418 ipmr_queue_xmit(skb2, cache, psend);
1419 } else {
1420 ipmr_queue_xmit(skb, cache, psend);
1421 return 0;
1422 }
1423 }
1424
1425dont_forward:
1426 if (!local)
1427 kfree_skb(skb);
1428 return 0;
1429}
1430
1431
1432/*
1433 * Multicast packets for forwarding arrive here
1434 */
1435
1436int ip_mr_input(struct sk_buff *skb)
1437{
1438 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001439 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001440 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 /* Packet is looped back after forward, it should not be
1443 forwarded second time, but still can be delivered locally.
1444 */
1445 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1446 goto dont_forward;
1447
1448 if (!local) {
1449 if (IPCB(skb)->opt.router_alert) {
1450 if (ip_call_ra_chain(skb))
1451 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001452 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 /* IGMPv1 (and broken IGMPv2 implementations sort of
1454 Cisco IOS <= 11.2(8)) do not put router alert
1455 option to IGMP packets destined to routable
1456 groups. It is very bad, because it means
1457 that we can forward NO IGMP messages.
1458 */
1459 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001460 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001461 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001462 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 read_unlock(&mrt_lock);
1464 return 0;
1465 }
1466 read_unlock(&mrt_lock);
1467 }
1468 }
1469
1470 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001471 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
1473 /*
1474 * No usable cache entry
1475 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001476 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 int vif;
1478
1479 if (local) {
1480 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1481 ip_local_deliver(skb);
1482 if (skb2 == NULL) {
1483 read_unlock(&mrt_lock);
1484 return -ENOBUFS;
1485 }
1486 skb = skb2;
1487 }
1488
1489 vif = ipmr_find_vif(skb->dev);
1490 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001491 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 read_unlock(&mrt_lock);
1493
1494 return err;
1495 }
1496 read_unlock(&mrt_lock);
1497 kfree_skb(skb);
1498 return -ENODEV;
1499 }
1500
1501 ip_mr_forward(skb, cache, local);
1502
1503 read_unlock(&mrt_lock);
1504
1505 if (local)
1506 return ip_local_deliver(skb);
1507
1508 return 0;
1509
1510dont_forward:
1511 if (local)
1512 return ip_local_deliver(skb);
1513 kfree_skb(skb);
1514 return 0;
1515}
1516
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001517#ifdef CONFIG_IP_PIMSM
1518static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001520 struct net_device *reg_dev = NULL;
1521 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001522 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001524 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 /*
1526 Check that:
1527 a. packet is really destinted to a multicast group
1528 b. packet is not a NULL-REGISTER
1529 c. packet is not truncated
1530 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001531 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001533 ntohs(encap->tot_len) + pimlen > skb->len)
1534 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001537 if (net->ipv4.mroute_reg_vif_num >= 0)
1538 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 if (reg_dev)
1540 dev_hold(reg_dev);
1541 read_unlock(&mrt_lock);
1542
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001543 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001544 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001546 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001548 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 skb->protocol = htons(ETH_P_IP);
1551 skb->ip_summed = 0;
1552 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001553 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001554 reg_dev->stats.rx_bytes += skb->len;
1555 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 nf_reset(skb);
1557 netif_rx(skb);
1558 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001561}
1562#endif
1563
1564#ifdef CONFIG_IP_PIMSM_V1
1565/*
1566 * Handle IGMP messages of PIMv1
1567 */
1568
1569int pim_rcv_v1(struct sk_buff * skb)
1570{
1571 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001572 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001573
1574 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1575 goto drop;
1576
1577 pim = igmp_hdr(skb);
1578
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001579 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001580 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1581 goto drop;
1582
1583 if (__pim_rcv(skb, sizeof(*pim))) {
1584drop:
1585 kfree_skb(skb);
1586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 return 0;
1588}
1589#endif
1590
1591#ifdef CONFIG_IP_PIMSM_V2
1592static int pim_rcv(struct sk_buff * skb)
1593{
1594 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001596 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 goto drop;
1598
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001599 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001600 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001602 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001603 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 goto drop;
1605
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001606 if (__pim_rcv(skb, sizeof(*pim))) {
1607drop:
1608 kfree_skb(skb);
1609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 return 0;
1611}
1612#endif
1613
1614static int
1615ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
1616{
1617 int ct;
1618 struct rtnexthop *nhp;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001619 struct net *net = mfc_net(c);
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001620 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 struct rtattr *mp_head;
1622
Nicolas Dichtel74381892010-03-25 23:45:35 +00001623 /* If cache is unresolved, don't try to parse IIF and OIF */
1624 if (c->mfc_parent > MAXVIFS)
1625 return -ENOENT;
1626
1627 if (VIF_EXISTS(net, c->mfc_parent))
1628 RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
Jianjun Kongc354e122008-11-03 00:28:02 -08001630 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Nicolas Dichtel74381892010-03-25 23:45:35 +00001633 if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1635 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001636 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 nhp->rtnh_flags = 0;
1638 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001639 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 nhp->rtnh_len = sizeof(*nhp);
1641 }
1642 }
1643 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001644 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 rtm->rtm_type = RTN_MULTICAST;
1646 return 1;
1647
1648rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001649 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return -EMSGSIZE;
1651}
1652
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001653int ipmr_get_route(struct net *net,
1654 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
1656 int err;
1657 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001658 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
1660 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001661 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
Jianjun Kongc354e122008-11-03 00:28:02 -08001663 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001664 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001665 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 struct net_device *dev;
1667 int vif;
1668
1669 if (nowait) {
1670 read_unlock(&mrt_lock);
1671 return -EAGAIN;
1672 }
1673
1674 dev = skb->dev;
1675 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1676 read_unlock(&mrt_lock);
1677 return -ENODEV;
1678 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001679 skb2 = skb_clone(skb, GFP_ATOMIC);
1680 if (!skb2) {
1681 read_unlock(&mrt_lock);
1682 return -ENOMEM;
1683 }
1684
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001685 skb_push(skb2, sizeof(struct iphdr));
1686 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001687 iph = ip_hdr(skb2);
1688 iph->ihl = sizeof(struct iphdr) >> 2;
1689 iph->saddr = rt->rt_src;
1690 iph->daddr = rt->rt_dst;
1691 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001692 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 read_unlock(&mrt_lock);
1694 return err;
1695 }
1696
1697 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1698 cache->mfc_flags |= MFC_NOTIFY;
1699 err = ipmr_fill_mroute(skb, cache, rtm);
1700 read_unlock(&mrt_lock);
1701 return err;
1702}
1703
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001704#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705/*
1706 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1707 */
1708struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001709 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 int ct;
1711};
1712
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001713static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1714 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 loff_t pos)
1716{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001717 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1718 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001720 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001721 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 }
1723 return NULL;
1724}
1725
1726static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001727 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001729 struct net *net = seq_file_net(seq);
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001732 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 : SEQ_START_TOKEN;
1734}
1735
1736static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1737{
1738 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001739 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741 ++*pos;
1742 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001743 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001744
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001745 while (++iter->ct < net->ipv4.maxvif) {
1746 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001748 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
1750 return NULL;
1751}
1752
1753static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001754 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
1756 read_unlock(&mrt_lock);
1757}
1758
1759static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1760{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001761 struct net *net = seq_file_net(seq);
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001764 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1766 } else {
1767 const struct vif_device *vif = v;
1768 const char *name = vif->dev ? vif->dev->name : "none";
1769
1770 seq_printf(seq,
1771 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001772 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001773 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 vif->bytes_out, vif->pkt_out,
1775 vif->flags, vif->local, vif->remote);
1776 }
1777 return 0;
1778}
1779
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001780static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 .start = ipmr_vif_seq_start,
1782 .next = ipmr_vif_seq_next,
1783 .stop = ipmr_vif_seq_stop,
1784 .show = ipmr_vif_seq_show,
1785};
1786
1787static int ipmr_vif_open(struct inode *inode, struct file *file)
1788{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001789 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1790 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791}
1792
Arjan van de Ven9a321442007-02-12 00:55:35 -08001793static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 .owner = THIS_MODULE,
1795 .open = ipmr_vif_open,
1796 .read = seq_read,
1797 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001798 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799};
1800
1801struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001802 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 struct mfc_cache **cache;
1804 int ct;
1805};
1806
1807
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001808static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1809 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
1811 struct mfc_cache *mfc;
1812
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001813 it->cache = net->ipv4.mfc_cache_array;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 read_lock(&mrt_lock);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001815 for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001816 for (mfc = net->ipv4.mfc_cache_array[it->ct];
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001817 mfc; mfc = mfc->next)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001818 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 return mfc;
1820 read_unlock(&mrt_lock);
1821
1822 it->cache = &mfc_unres_queue;
1823 spin_lock_bh(&mfc_unres_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001824 for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001825 if (net_eq(mfc_net(mfc), net) &&
1826 pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 return mfc;
1828 spin_unlock_bh(&mfc_unres_lock);
1829
1830 it->cache = NULL;
1831 return NULL;
1832}
1833
1834
1835static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1836{
1837 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001838 struct net *net = seq_file_net(seq);
1839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 it->cache = NULL;
1841 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001842 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 : SEQ_START_TOKEN;
1844}
1845
1846static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1847{
1848 struct mfc_cache *mfc = v;
1849 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001850 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 ++*pos;
1853
1854 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001855 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
1857 if (mfc->next)
1858 return mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001859
1860 if (it->cache == &mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 goto end_of_list;
1862
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001863 BUG_ON(it->cache != net->ipv4.mfc_cache_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 while (++it->ct < MFC_LINES) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001866 mfc = net->ipv4.mfc_cache_array[it->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 if (mfc)
1868 return mfc;
1869 }
1870
1871 /* exhausted cache_array, show unresolved */
1872 read_unlock(&mrt_lock);
1873 it->cache = &mfc_unres_queue;
1874 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 spin_lock_bh(&mfc_unres_lock);
1877 mfc = mfc_unres_queue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001878 while (mfc && !net_eq(mfc_net(mfc), net))
1879 mfc = mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001880 if (mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return mfc;
1882
1883 end_of_list:
1884 spin_unlock_bh(&mfc_unres_lock);
1885 it->cache = NULL;
1886
1887 return NULL;
1888}
1889
1890static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1891{
1892 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001893 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 if (it->cache == &mfc_unres_queue)
1896 spin_unlock_bh(&mfc_unres_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001897 else if (it->cache == net->ipv4.mfc_cache_array)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 read_unlock(&mrt_lock);
1899}
1900
1901static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1902{
1903 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001904 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001907 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1909 } else {
1910 const struct mfc_cache *mfc = v;
1911 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001912
Benjamin Thery999890b2008-12-03 22:22:16 -08001913 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 (unsigned long) mfc->mfc_mcastgrp,
1915 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001916 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918 if (it->cache != &mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001919 seq_printf(seq, " %8lu %8lu %8lu",
1920 mfc->mfc_un.res.pkt,
1921 mfc->mfc_un.res.bytes,
1922 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001923 for (n = mfc->mfc_un.res.minvif;
1924 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001925 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001926 mfc->mfc_un.res.ttls[n] < 255)
1927 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001928 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 n, mfc->mfc_un.res.ttls[n]);
1930 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001931 } else {
1932 /* unresolved mfc_caches don't contain
1933 * pkt, bytes and wrong_if values
1934 */
1935 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937 seq_putc(seq, '\n');
1938 }
1939 return 0;
1940}
1941
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001942static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 .start = ipmr_mfc_seq_start,
1944 .next = ipmr_mfc_seq_next,
1945 .stop = ipmr_mfc_seq_stop,
1946 .show = ipmr_mfc_seq_show,
1947};
1948
1949static int ipmr_mfc_open(struct inode *inode, struct file *file)
1950{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001951 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1952 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
Arjan van de Ven9a321442007-02-12 00:55:35 -08001955static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 .owner = THIS_MODULE,
1957 .open = ipmr_mfc_open,
1958 .read = seq_read,
1959 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001960 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001962#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
1964#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001965static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001967 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968};
1969#endif
1970
1971
1972/*
1973 * Setup for IP multicast routing
1974 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001975static int __net_init ipmr_net_init(struct net *net)
1976{
1977 int err = 0;
1978
1979 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1980 GFP_KERNEL);
1981 if (!net->ipv4.vif_table) {
1982 err = -ENOMEM;
1983 goto fail;
1984 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001985
1986 /* Forwarding cache */
1987 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
1988 sizeof(struct mfc_cache *),
1989 GFP_KERNEL);
1990 if (!net->ipv4.mfc_cache_array) {
1991 err = -ENOMEM;
1992 goto fail_mfc_cache;
1993 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001994
1995#ifdef CONFIG_IP_PIMSM
1996 net->ipv4.mroute_reg_vif_num = -1;
1997#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001998
1999#ifdef CONFIG_PROC_FS
2000 err = -ENOMEM;
2001 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
2002 goto proc_vif_fail;
2003 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
2004 goto proc_cache_fail;
2005#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002006 return 0;
2007
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002008#ifdef CONFIG_PROC_FS
2009proc_cache_fail:
2010 proc_net_remove(net, "ip_mr_vif");
2011proc_vif_fail:
2012 kfree(net->ipv4.mfc_cache_array);
2013#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002014fail_mfc_cache:
2015 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002016fail:
2017 return err;
2018}
2019
2020static void __net_exit ipmr_net_exit(struct net *net)
2021{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002022#ifdef CONFIG_PROC_FS
2023 proc_net_remove(net, "ip_mr_cache");
2024 proc_net_remove(net, "ip_mr_vif");
2025#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002026 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002027 kfree(net->ipv4.vif_table);
2028}
2029
2030static struct pernet_operations ipmr_net_ops = {
2031 .init = ipmr_net_init,
2032 .exit = ipmr_net_exit,
2033};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002034
Wang Chen03d2f892008-07-03 12:13:36 +08002035int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036{
Wang Chen03d2f892008-07-03 12:13:36 +08002037 int err;
2038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2040 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002041 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002042 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002043 if (!mrt_cachep)
2044 return -ENOMEM;
2045
Benjamin Therycf958ae32009-01-22 04:56:16 +00002046 err = register_pernet_subsys(&ipmr_net_ops);
2047 if (err)
2048 goto reg_pernet_fail;
2049
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08002050 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
Wang Chen03d2f892008-07-03 12:13:36 +08002051 err = register_netdevice_notifier(&ip_mr_notifier);
2052 if (err)
2053 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002054#ifdef CONFIG_IP_PIMSM_V2
2055 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2056 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2057 err = -EAGAIN;
2058 goto add_proto_fail;
2059 }
2060#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002061 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002062
Tom Goff403dbb92009-06-14 03:16:13 -07002063#ifdef CONFIG_IP_PIMSM_V2
2064add_proto_fail:
2065 unregister_netdevice_notifier(&ip_mr_notifier);
2066#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002067reg_notif_fail:
2068 del_timer(&ipmr_expire_timer);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002069 unregister_pernet_subsys(&ipmr_net_ops);
2070reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002071 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002072 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073}