blob: ec19a890c9a0eb02ba9deec1b099422690e621c0 [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
Andreas Meissnerbbd72542010-05-10 04:47:49 -0700757 if (atomic_read(&net->ipv4.cache_resolve_queue_len) == 1)
758 mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
760
761 /*
762 * See if we can append the packet
763 */
764 if (c->mfc_un.unres.unresolved.qlen>3) {
765 kfree_skb(skb);
766 err = -ENOBUFS;
767 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800768 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 err = 0;
770 }
771
772 spin_unlock_bh(&mfc_unres_lock);
773 return err;
774}
775
776/*
777 * MFC cache manipulation by user space mroute daemon
778 */
779
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000780static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
782 int line;
783 struct mfc_cache *c, **cp;
784
Jianjun Kongc354e122008-11-03 00:28:02 -0800785 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000787 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000788 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
790 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
791 write_lock_bh(&mrt_lock);
792 *cp = c->next;
793 write_unlock_bh(&mrt_lock);
794
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000795 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return 0;
797 }
798 }
799 return -ENOENT;
800}
801
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000802static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 int line;
805 struct mfc_cache *uc, *c, **cp;
806
Patrick McHardya50436f22010-03-17 06:04:14 +0000807 if (mfc->mfcc_parent >= MAXVIFS)
808 return -ENFILE;
809
Jianjun Kongc354e122008-11-03 00:28:02 -0800810 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000812 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000813 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
815 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
816 break;
817 }
818
819 if (c != NULL) {
820 write_lock_bh(&mrt_lock);
821 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700822 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 if (!mrtsock)
824 c->mfc_flags |= MFC_STATIC;
825 write_unlock_bh(&mrt_lock);
826 return 0;
827 }
828
Joe Perchesf97c1e02007-12-16 13:45:43 -0800829 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return -EINVAL;
831
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000832 c = ipmr_cache_alloc(net);
Jianjun Kongc354e122008-11-03 00:28:02 -0800833 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return -ENOMEM;
835
Jianjun Kongc354e122008-11-03 00:28:02 -0800836 c->mfc_origin = mfc->mfcc_origin.s_addr;
837 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
838 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700839 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (!mrtsock)
841 c->mfc_flags |= MFC_STATIC;
842
843 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000844 c->next = net->ipv4.mfc_cache_array[line];
845 net->ipv4.mfc_cache_array[line] = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 write_unlock_bh(&mrt_lock);
847
848 /*
849 * Check to see if we resolved a queued list. If so we
850 * need to send on the frames and tidy up.
851 */
852 spin_lock_bh(&mfc_unres_lock);
853 for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
854 cp = &uc->next) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000855 if (net_eq(mfc_net(uc), net) &&
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000856 uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
858 *cp = uc->next;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000859 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 break;
861 }
862 }
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000863 if (mfc_unres_queue == NULL)
864 del_timer(&ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 spin_unlock_bh(&mfc_unres_lock);
866
867 if (uc) {
868 ipmr_cache_resolve(uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000869 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871 return 0;
872}
873
874/*
875 * Close the multicast socket, and clear the vif tables etc
876 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900877
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000878static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000881 LIST_HEAD(list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /*
884 * Shut down all active vif entries
885 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000886 for (i = 0; i < net->ipv4.maxvif; i++) {
887 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000888 vif_delete(net, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000890 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892 /*
893 * Wipe the cache
894 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800895 for (i=0; i<MFC_LINES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 struct mfc_cache *c, **cp;
897
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000898 cp = &net->ipv4.mfc_cache_array[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 while ((c = *cp) != NULL) {
900 if (c->mfc_flags&MFC_STATIC) {
901 cp = &c->next;
902 continue;
903 }
904 write_lock_bh(&mrt_lock);
905 *cp = c->next;
906 write_unlock_bh(&mrt_lock);
907
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000908 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 }
910 }
911
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000912 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000913 struct mfc_cache *c, **cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 spin_lock_bh(&mfc_unres_lock);
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000916 cp = &mfc_unres_queue;
917 while ((c = *cp) != NULL) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000918 if (!net_eq(mfc_net(c), net)) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000919 cp = &c->next;
920 continue;
921 }
922 *cp = c->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 ipmr_destroy_unres(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926 spin_unlock_bh(&mfc_unres_lock);
927 }
928}
929
930static void mrtsock_destruct(struct sock *sk)
931{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000932 struct net *net = sock_net(sk);
933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000935 if (sk == net->ipv4.mroute_sk) {
936 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000939 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 write_unlock_bh(&mrt_lock);
941
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000942 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944 rtnl_unlock();
945}
946
947/*
948 * Socket options and virtual interface manipulation. The whole
949 * virtual interface system is a complete heap, but unfortunately
950 * that's how BSD mrouted happens to think. Maybe one day with a proper
951 * MOSPF/PIM router set up we can clean this up.
952 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900953
David S. Millerb7058842009-09-30 16:12:20 -0700954int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 int ret;
957 struct vifctl vif;
958 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000959 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900960
Stephen Hemminger132adf52007-03-08 20:44:43 -0800961 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000962 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 return -EACCES;
964 }
965
Stephen Hemminger132adf52007-03-08 20:44:43 -0800966 switch (optname) {
967 case MRT_INIT:
968 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000969 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800970 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800971 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800972 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Stephen Hemminger132adf52007-03-08 20:44:43 -0800974 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000975 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800977 return -EADDRINUSE;
978 }
979
980 ret = ip_ra_control(sk, 1, mrtsock_destruct);
981 if (ret == 0) {
982 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000983 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800984 write_unlock_bh(&mrt_lock);
985
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000986 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800987 }
988 rtnl_unlock();
989 return ret;
990 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000991 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800992 return -EACCES;
993 return ip_ra_control(sk, 0, NULL);
994 case MRT_ADD_VIF:
995 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800996 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800997 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800998 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800999 return -EFAULT;
1000 if (vif.vifc_vifi >= MAXVIFS)
1001 return -ENFILE;
1002 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001003 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001004 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001005 } else {
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001006 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001007 }
1008 rtnl_unlock();
1009 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 /*
1012 * Manipulate the forwarding caches. These live
1013 * in a sort of kernel/user symbiosis.
1014 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001015 case MRT_ADD_MFC:
1016 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -08001017 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001018 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001019 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001020 return -EFAULT;
1021 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001022 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001023 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001024 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001025 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001026 rtnl_unlock();
1027 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 /*
1029 * Control PIM assert.
1030 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001031 case MRT_ASSERT:
1032 {
1033 int v;
1034 if (get_user(v,(int __user *)optval))
1035 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001036 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001037 return 0;
1038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001040 case MRT_PIM:
1041 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001042 int v;
1043
Stephen Hemminger132adf52007-03-08 20:44:43 -08001044 if (get_user(v,(int __user *)optval))
1045 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001046 v = (v) ? 1 : 0;
1047
Stephen Hemminger132adf52007-03-08 20:44:43 -08001048 rtnl_lock();
1049 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001050 if (v != net->ipv4.mroute_do_pim) {
1051 net->ipv4.mroute_do_pim = v;
1052 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001054 rtnl_unlock();
1055 return ret;
1056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001058 /*
1059 * Spurious command, or MRT_VERSION which you cannot
1060 * set.
1061 */
1062 default:
1063 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 }
1065}
1066
1067/*
1068 * Getsock opt support for the multicast routing system.
1069 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001070
Jianjun Kongc354e122008-11-03 00:28:02 -08001071int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
1073 int olr;
1074 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001075 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Jianjun Kongc354e122008-11-03 00:28:02 -08001077 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078#ifdef CONFIG_IP_PIMSM
1079 optname!=MRT_PIM &&
1080#endif
1081 optname!=MRT_ASSERT)
1082 return -ENOPROTOOPT;
1083
1084 if (get_user(olr, optlen))
1085 return -EFAULT;
1086
1087 olr = min_t(unsigned int, olr, sizeof(int));
1088 if (olr < 0)
1089 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001090
Jianjun Kongc354e122008-11-03 00:28:02 -08001091 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001093 if (optname == MRT_VERSION)
1094 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001096 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001097 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098#endif
1099 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001100 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001101 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return -EFAULT;
1103 return 0;
1104}
1105
1106/*
1107 * The IP multicast ioctl support routines.
1108 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1111{
1112 struct sioc_sg_req sr;
1113 struct sioc_vif_req vr;
1114 struct vif_device *vif;
1115 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001116 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001117
Stephen Hemminger132adf52007-03-08 20:44:43 -08001118 switch (cmd) {
1119 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001120 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001121 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001122 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001123 return -EINVAL;
1124 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001125 vif = &net->ipv4.vif_table[vr.vifi];
1126 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001127 vr.icount = vif->pkt_in;
1128 vr.ocount = vif->pkt_out;
1129 vr.ibytes = vif->bytes_in;
1130 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001132
Jianjun Kongc354e122008-11-03 00:28:02 -08001133 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001135 return 0;
1136 }
1137 read_unlock(&mrt_lock);
1138 return -EADDRNOTAVAIL;
1139 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001140 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001141 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Stephen Hemminger132adf52007-03-08 20:44:43 -08001143 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001144 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001145 if (c) {
1146 sr.pktcnt = c->mfc_un.res.pkt;
1147 sr.bytecnt = c->mfc_un.res.bytes;
1148 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001150
Jianjun Kongc354e122008-11-03 00:28:02 -08001151 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001152 return -EFAULT;
1153 return 0;
1154 }
1155 read_unlock(&mrt_lock);
1156 return -EADDRNOTAVAIL;
1157 default:
1158 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160}
1161
1162
1163static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1164{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001165 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001166 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 struct vif_device *v;
1168 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001169 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (event != NETDEV_UNREGISTER)
1172 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001173 v = &net->ipv4.vif_table[0];
1174 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001175 if (v->dev == dev)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001176 vif_delete(net, ct, 1, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001178 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return NOTIFY_DONE;
1180}
1181
1182
Jianjun Kongc354e122008-11-03 00:28:02 -08001183static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 .notifier_call = ipmr_device_event,
1185};
1186
1187/*
1188 * Encapsulate a packet by attaching a valid IPIP header to it.
1189 * This avoids tunnel drivers and other mess and gives us the speed so
1190 * important for multicast video.
1191 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001192
Al Viro114c7842006-09-27 18:39:29 -07001193static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001195 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001196 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001197
1198 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001199 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001200 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001201 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001204 iph->tos = old_iph->tos;
1205 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 iph->frag_off = 0;
1207 iph->daddr = daddr;
1208 iph->saddr = saddr;
1209 iph->protocol = IPPROTO_IPIP;
1210 iph->ihl = 5;
1211 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001212 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 ip_send_check(iph);
1214
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1216 nf_reset(skb);
1217}
1218
1219static inline int ipmr_forward_finish(struct sk_buff *skb)
1220{
1221 struct ip_options * opt = &(IPCB(skb)->opt);
1222
Eric Dumazetadf30902009-06-02 05:19:30 +00001223 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 if (unlikely(opt->optlen))
1226 ip_forward_options(skb);
1227
1228 return dst_output(skb);
1229}
1230
1231/*
1232 * Processing handlers for ipmr_forward
1233 */
1234
1235static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
1236{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001237 struct net *net = mfc_net(c);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001238 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001239 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 struct net_device *dev;
1241 struct rtable *rt;
1242 int encap = 0;
1243
1244 if (vif->dev == NULL)
1245 goto out_free;
1246
1247#ifdef CONFIG_IP_PIMSM
1248 if (vif->flags & VIFF_REGISTER) {
1249 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001250 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001251 vif->dev->stats.tx_bytes += skb->len;
1252 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001253 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001254 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 }
1256#endif
1257
1258 if (vif->flags&VIFF_TUNNEL) {
1259 struct flowi fl = { .oif = vif->link,
1260 .nl_u = { .ip4_u =
1261 { .daddr = vif->remote,
1262 .saddr = vif->local,
1263 .tos = RT_TOS(iph->tos) } },
1264 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001265 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 goto out_free;
1267 encap = sizeof(struct iphdr);
1268 } else {
1269 struct flowi fl = { .oif = vif->link,
1270 .nl_u = { .ip4_u =
1271 { .daddr = iph->daddr,
1272 .tos = RT_TOS(iph->tos) } },
1273 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001274 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 goto out_free;
1276 }
1277
1278 dev = rt->u.dst.dev;
1279
1280 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1281 /* Do not fragment multicasts. Alas, IPv4 does not
1282 allow to send ICMP, so that packets will disappear
1283 to blackhole.
1284 */
1285
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001286 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 ip_rt_put(rt);
1288 goto out_free;
1289 }
1290
1291 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1292
1293 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001294 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 goto out_free;
1296 }
1297
1298 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001299 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Eric Dumazetadf30902009-06-02 05:19:30 +00001301 skb_dst_drop(skb);
1302 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001303 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 /* FIXME: forward and output firewalls used to be called here.
1306 * What do we do with netfilter? -- RR */
1307 if (vif->flags & VIFF_TUNNEL) {
1308 ip_encap(skb, vif->local, vif->remote);
1309 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001310 vif->dev->stats.tx_packets++;
1311 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
1313
1314 IPCB(skb)->flags |= IPSKB_FORWARDED;
1315
1316 /*
1317 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1318 * not only before forwarding, but after forwarding on all output
1319 * interfaces. It is clear, if mrouter runs a multicasting
1320 * program, it should receive packets not depending to what interface
1321 * program is joined.
1322 * If we will not make it, the program will have to join on all
1323 * interfaces. On the other hand, multihoming host (or router, but
1324 * not mrouter) cannot join to more than one interface - it will
1325 * result in receiving multiple packets.
1326 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001327 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 ipmr_forward_finish);
1329 return;
1330
1331out_free:
1332 kfree_skb(skb);
1333 return;
1334}
1335
1336static int ipmr_find_vif(struct net_device *dev)
1337{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001338 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001340 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1341 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 break;
1343 }
1344 return ct;
1345}
1346
1347/* "local" means that we should preserve one skb (for local delivery) */
1348
1349static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
1350{
1351 int psend = -1;
1352 int vif, ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001353 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 vif = cache->mfc_parent;
1356 cache->mfc_un.res.pkt++;
1357 cache->mfc_un.res.bytes += skb->len;
1358
1359 /*
1360 * Wrong interface: drop packet and (maybe) send PIM assert.
1361 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001362 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 int true_vifi;
1364
Eric Dumazet511c3f92009-06-02 05:14:27 +00001365 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 /* It is our own packet, looped back.
1367 Very complicated situation...
1368
1369 The best workaround until routing daemons will be
1370 fixed is not to redistribute packet, if it was
1371 send through wrong interface. It means, that
1372 multicast applications WILL NOT work for
1373 (S,G), which have default multicast route pointing
1374 to wrong oif. In any case, it is not a good
1375 idea to use multicasting applications on router.
1376 */
1377 goto dont_forward;
1378 }
1379
1380 cache->mfc_un.res.wrong_if++;
1381 true_vifi = ipmr_find_vif(skb->dev);
1382
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001383 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 /* pimsm uses asserts, when switching from RPT to SPT,
1385 so that we cannot check that packet arrived on an oif.
1386 It is bad, but otherwise we would need to move pretty
1387 large chunk of pimd to kernel. Ough... --ANK
1388 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001389 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001390 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001391 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1393 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001394 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 }
1396 goto dont_forward;
1397 }
1398
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001399 net->ipv4.vif_table[vif].pkt_in++;
1400 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 /*
1403 * Forward the frame
1404 */
1405 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001406 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (psend != -1) {
1408 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1409 if (skb2)
1410 ipmr_queue_xmit(skb2, cache, psend);
1411 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001412 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
1414 }
1415 if (psend != -1) {
1416 if (local) {
1417 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1418 if (skb2)
1419 ipmr_queue_xmit(skb2, cache, psend);
1420 } else {
1421 ipmr_queue_xmit(skb, cache, psend);
1422 return 0;
1423 }
1424 }
1425
1426dont_forward:
1427 if (!local)
1428 kfree_skb(skb);
1429 return 0;
1430}
1431
1432
1433/*
1434 * Multicast packets for forwarding arrive here
1435 */
1436
1437int ip_mr_input(struct sk_buff *skb)
1438{
1439 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001440 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001441 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
1443 /* Packet is looped back after forward, it should not be
1444 forwarded second time, but still can be delivered locally.
1445 */
1446 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1447 goto dont_forward;
1448
1449 if (!local) {
1450 if (IPCB(skb)->opt.router_alert) {
1451 if (ip_call_ra_chain(skb))
1452 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001453 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 /* IGMPv1 (and broken IGMPv2 implementations sort of
1455 Cisco IOS <= 11.2(8)) do not put router alert
1456 option to IGMP packets destined to routable
1457 groups. It is very bad, because it means
1458 that we can forward NO IGMP messages.
1459 */
1460 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001461 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001462 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001463 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 read_unlock(&mrt_lock);
1465 return 0;
1466 }
1467 read_unlock(&mrt_lock);
1468 }
1469 }
1470
1471 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001472 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 /*
1475 * No usable cache entry
1476 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001477 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 int vif;
1479
1480 if (local) {
1481 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1482 ip_local_deliver(skb);
1483 if (skb2 == NULL) {
1484 read_unlock(&mrt_lock);
1485 return -ENOBUFS;
1486 }
1487 skb = skb2;
1488 }
1489
1490 vif = ipmr_find_vif(skb->dev);
1491 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001492 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 read_unlock(&mrt_lock);
1494
1495 return err;
1496 }
1497 read_unlock(&mrt_lock);
1498 kfree_skb(skb);
1499 return -ENODEV;
1500 }
1501
1502 ip_mr_forward(skb, cache, local);
1503
1504 read_unlock(&mrt_lock);
1505
1506 if (local)
1507 return ip_local_deliver(skb);
1508
1509 return 0;
1510
1511dont_forward:
1512 if (local)
1513 return ip_local_deliver(skb);
1514 kfree_skb(skb);
1515 return 0;
1516}
1517
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001518#ifdef CONFIG_IP_PIMSM
1519static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001521 struct net_device *reg_dev = NULL;
1522 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001523 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001525 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 /*
1527 Check that:
1528 a. packet is really destinted to a multicast group
1529 b. packet is not a NULL-REGISTER
1530 c. packet is not truncated
1531 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001532 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001534 ntohs(encap->tot_len) + pimlen > skb->len)
1535 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001538 if (net->ipv4.mroute_reg_vif_num >= 0)
1539 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if (reg_dev)
1541 dev_hold(reg_dev);
1542 read_unlock(&mrt_lock);
1543
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001544 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001545 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001547 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001549 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 skb->protocol = htons(ETH_P_IP);
1552 skb->ip_summed = 0;
1553 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001554 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001555 reg_dev->stats.rx_bytes += skb->len;
1556 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 nf_reset(skb);
1558 netif_rx(skb);
1559 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001562}
1563#endif
1564
1565#ifdef CONFIG_IP_PIMSM_V1
1566/*
1567 * Handle IGMP messages of PIMv1
1568 */
1569
1570int pim_rcv_v1(struct sk_buff * skb)
1571{
1572 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001573 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001574
1575 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1576 goto drop;
1577
1578 pim = igmp_hdr(skb);
1579
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001580 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001581 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1582 goto drop;
1583
1584 if (__pim_rcv(skb, sizeof(*pim))) {
1585drop:
1586 kfree_skb(skb);
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 return 0;
1589}
1590#endif
1591
1592#ifdef CONFIG_IP_PIMSM_V2
1593static int pim_rcv(struct sk_buff * skb)
1594{
1595 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001597 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 goto drop;
1599
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001600 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001601 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001603 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001604 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 goto drop;
1606
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001607 if (__pim_rcv(skb, sizeof(*pim))) {
1608drop:
1609 kfree_skb(skb);
1610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 return 0;
1612}
1613#endif
1614
1615static int
1616ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
1617{
1618 int ct;
1619 struct rtnexthop *nhp;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001620 struct net *net = mfc_net(c);
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001621 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 struct rtattr *mp_head;
1623
Nicolas Dichtel74381892010-03-25 23:45:35 +00001624 /* If cache is unresolved, don't try to parse IIF and OIF */
1625 if (c->mfc_parent > MAXVIFS)
1626 return -ENOENT;
1627
1628 if (VIF_EXISTS(net, c->mfc_parent))
1629 RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Jianjun Kongc354e122008-11-03 00:28:02 -08001631 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Nicolas Dichtel74381892010-03-25 23:45:35 +00001634 if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1636 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001637 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 nhp->rtnh_flags = 0;
1639 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001640 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 nhp->rtnh_len = sizeof(*nhp);
1642 }
1643 }
1644 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001645 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 rtm->rtm_type = RTN_MULTICAST;
1647 return 1;
1648
1649rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001650 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 return -EMSGSIZE;
1652}
1653
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001654int ipmr_get_route(struct net *net,
1655 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 int err;
1658 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001659 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001662 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Jianjun Kongc354e122008-11-03 00:28:02 -08001664 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001665 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001666 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 struct net_device *dev;
1668 int vif;
1669
1670 if (nowait) {
1671 read_unlock(&mrt_lock);
1672 return -EAGAIN;
1673 }
1674
1675 dev = skb->dev;
1676 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1677 read_unlock(&mrt_lock);
1678 return -ENODEV;
1679 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001680 skb2 = skb_clone(skb, GFP_ATOMIC);
1681 if (!skb2) {
1682 read_unlock(&mrt_lock);
1683 return -ENOMEM;
1684 }
1685
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001686 skb_push(skb2, sizeof(struct iphdr));
1687 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001688 iph = ip_hdr(skb2);
1689 iph->ihl = sizeof(struct iphdr) >> 2;
1690 iph->saddr = rt->rt_src;
1691 iph->daddr = rt->rt_dst;
1692 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001693 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 read_unlock(&mrt_lock);
1695 return err;
1696 }
1697
1698 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1699 cache->mfc_flags |= MFC_NOTIFY;
1700 err = ipmr_fill_mroute(skb, cache, rtm);
1701 read_unlock(&mrt_lock);
1702 return err;
1703}
1704
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001705#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706/*
1707 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1708 */
1709struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001710 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 int ct;
1712};
1713
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001714static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1715 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 loff_t pos)
1717{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001718 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1719 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001721 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001722 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
1724 return NULL;
1725}
1726
1727static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001728 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001730 struct net *net = seq_file_net(seq);
1731
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001733 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 : SEQ_START_TOKEN;
1735}
1736
1737static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1738{
1739 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001740 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
1742 ++*pos;
1743 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001744 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001745
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001746 while (++iter->ct < net->ipv4.maxvif) {
1747 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001749 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 }
1751 return NULL;
1752}
1753
1754static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001755 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
1757 read_unlock(&mrt_lock);
1758}
1759
1760static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1761{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001762 struct net *net = seq_file_net(seq);
1763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001765 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1767 } else {
1768 const struct vif_device *vif = v;
1769 const char *name = vif->dev ? vif->dev->name : "none";
1770
1771 seq_printf(seq,
1772 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001773 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001774 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 vif->bytes_out, vif->pkt_out,
1776 vif->flags, vif->local, vif->remote);
1777 }
1778 return 0;
1779}
1780
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001781static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 .start = ipmr_vif_seq_start,
1783 .next = ipmr_vif_seq_next,
1784 .stop = ipmr_vif_seq_stop,
1785 .show = ipmr_vif_seq_show,
1786};
1787
1788static int ipmr_vif_open(struct inode *inode, struct file *file)
1789{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001790 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1791 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792}
1793
Arjan van de Ven9a321442007-02-12 00:55:35 -08001794static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 .owner = THIS_MODULE,
1796 .open = ipmr_vif_open,
1797 .read = seq_read,
1798 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001799 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800};
1801
1802struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001803 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 struct mfc_cache **cache;
1805 int ct;
1806};
1807
1808
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001809static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1810 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811{
1812 struct mfc_cache *mfc;
1813
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001814 it->cache = net->ipv4.mfc_cache_array;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 read_lock(&mrt_lock);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001816 for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001817 for (mfc = net->ipv4.mfc_cache_array[it->ct];
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001818 mfc; mfc = mfc->next)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001819 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 return mfc;
1821 read_unlock(&mrt_lock);
1822
1823 it->cache = &mfc_unres_queue;
1824 spin_lock_bh(&mfc_unres_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001825 for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001826 if (net_eq(mfc_net(mfc), net) &&
1827 pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 return mfc;
1829 spin_unlock_bh(&mfc_unres_lock);
1830
1831 it->cache = NULL;
1832 return NULL;
1833}
1834
1835
1836static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1837{
1838 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001839 struct net *net = seq_file_net(seq);
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 it->cache = NULL;
1842 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001843 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 : SEQ_START_TOKEN;
1845}
1846
1847static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1848{
1849 struct mfc_cache *mfc = v;
1850 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001851 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 ++*pos;
1854
1855 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001856 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 if (mfc->next)
1859 return mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001860
1861 if (it->cache == &mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 goto end_of_list;
1863
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001864 BUG_ON(it->cache != net->ipv4.mfc_cache_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 while (++it->ct < MFC_LINES) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001867 mfc = net->ipv4.mfc_cache_array[it->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (mfc)
1869 return mfc;
1870 }
1871
1872 /* exhausted cache_array, show unresolved */
1873 read_unlock(&mrt_lock);
1874 it->cache = &mfc_unres_queue;
1875 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 spin_lock_bh(&mfc_unres_lock);
1878 mfc = mfc_unres_queue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001879 while (mfc && !net_eq(mfc_net(mfc), net))
1880 mfc = mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001881 if (mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 return mfc;
1883
1884 end_of_list:
1885 spin_unlock_bh(&mfc_unres_lock);
1886 it->cache = NULL;
1887
1888 return NULL;
1889}
1890
1891static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1892{
1893 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001894 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 if (it->cache == &mfc_unres_queue)
1897 spin_unlock_bh(&mfc_unres_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001898 else if (it->cache == net->ipv4.mfc_cache_array)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 read_unlock(&mrt_lock);
1900}
1901
1902static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1903{
1904 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001905 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001908 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1910 } else {
1911 const struct mfc_cache *mfc = v;
1912 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001913
Benjamin Thery999890b2008-12-03 22:22:16 -08001914 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 (unsigned long) mfc->mfc_mcastgrp,
1916 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001917 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919 if (it->cache != &mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001920 seq_printf(seq, " %8lu %8lu %8lu",
1921 mfc->mfc_un.res.pkt,
1922 mfc->mfc_un.res.bytes,
1923 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001924 for (n = mfc->mfc_un.res.minvif;
1925 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001926 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001927 mfc->mfc_un.res.ttls[n] < 255)
1928 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001929 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 n, mfc->mfc_un.res.ttls[n]);
1931 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001932 } else {
1933 /* unresolved mfc_caches don't contain
1934 * pkt, bytes and wrong_if values
1935 */
1936 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
1938 seq_putc(seq, '\n');
1939 }
1940 return 0;
1941}
1942
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001943static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 .start = ipmr_mfc_seq_start,
1945 .next = ipmr_mfc_seq_next,
1946 .stop = ipmr_mfc_seq_stop,
1947 .show = ipmr_mfc_seq_show,
1948};
1949
1950static int ipmr_mfc_open(struct inode *inode, struct file *file)
1951{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001952 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1953 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954}
1955
Arjan van de Ven9a321442007-02-12 00:55:35 -08001956static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 .owner = THIS_MODULE,
1958 .open = ipmr_mfc_open,
1959 .read = seq_read,
1960 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001961 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001963#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
1965#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001966static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001968 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969};
1970#endif
1971
1972
1973/*
1974 * Setup for IP multicast routing
1975 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001976static int __net_init ipmr_net_init(struct net *net)
1977{
1978 int err = 0;
1979
1980 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1981 GFP_KERNEL);
1982 if (!net->ipv4.vif_table) {
1983 err = -ENOMEM;
1984 goto fail;
1985 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001986
1987 /* Forwarding cache */
1988 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
1989 sizeof(struct mfc_cache *),
1990 GFP_KERNEL);
1991 if (!net->ipv4.mfc_cache_array) {
1992 err = -ENOMEM;
1993 goto fail_mfc_cache;
1994 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001995
1996#ifdef CONFIG_IP_PIMSM
1997 net->ipv4.mroute_reg_vif_num = -1;
1998#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001999
2000#ifdef CONFIG_PROC_FS
2001 err = -ENOMEM;
2002 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
2003 goto proc_vif_fail;
2004 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
2005 goto proc_cache_fail;
2006#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002007 return 0;
2008
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002009#ifdef CONFIG_PROC_FS
2010proc_cache_fail:
2011 proc_net_remove(net, "ip_mr_vif");
2012proc_vif_fail:
2013 kfree(net->ipv4.mfc_cache_array);
2014#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002015fail_mfc_cache:
2016 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002017fail:
2018 return err;
2019}
2020
2021static void __net_exit ipmr_net_exit(struct net *net)
2022{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002023#ifdef CONFIG_PROC_FS
2024 proc_net_remove(net, "ip_mr_cache");
2025 proc_net_remove(net, "ip_mr_vif");
2026#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002027 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002028 kfree(net->ipv4.vif_table);
2029}
2030
2031static struct pernet_operations ipmr_net_ops = {
2032 .init = ipmr_net_init,
2033 .exit = ipmr_net_exit,
2034};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002035
Wang Chen03d2f892008-07-03 12:13:36 +08002036int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037{
Wang Chen03d2f892008-07-03 12:13:36 +08002038 int err;
2039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2041 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002042 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002043 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002044 if (!mrt_cachep)
2045 return -ENOMEM;
2046
Benjamin Therycf958ae32009-01-22 04:56:16 +00002047 err = register_pernet_subsys(&ipmr_net_ops);
2048 if (err)
2049 goto reg_pernet_fail;
2050
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08002051 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
Wang Chen03d2f892008-07-03 12:13:36 +08002052 err = register_netdevice_notifier(&ip_mr_notifier);
2053 if (err)
2054 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002055#ifdef CONFIG_IP_PIMSM_V2
2056 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2057 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2058 err = -EAGAIN;
2059 goto add_proto_fail;
2060 }
2061#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002062 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002063
Tom Goff403dbb92009-06-14 03:16:13 -07002064#ifdef CONFIG_IP_PIMSM_V2
2065add_proto_fail:
2066 unregister_netdevice_notifier(&ip_mr_notifier);
2067#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002068reg_notif_fail:
2069 del_timer(&ipmr_expire_timer);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002070 unregister_pernet_subsys(&ipmr_net_ops);
2071reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002072 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002073 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074}