blob: f8e25c8ba07099128a1db7dce7c4c087b2db992d [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 -070083/* Special spinlock for queue of unresolved entries */
84static DEFINE_SPINLOCK(mfc_unres_lock);
85
86/* We return to original Alan's scheme. Hash table of resolved
87 entries is changed only in process context and protected
88 with weak lock mrt_lock. Queue of unresolved entries is protected
89 with strong spinlock mfc_unres_lock.
90
91 In this case data path is free of exclusive locks at all.
92 */
93
Christoph Lametere18b8902006-12-06 20:33:20 -080094static struct kmem_cache *mrt_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Patrick McHardyd658f8a2010-04-13 05:03:20 +000096static int ip_mr_forward(struct net *net, struct sk_buff *skb,
97 struct mfc_cache *cache, int local);
Benjamin Thery4feb88e2009-01-22 04:56:23 +000098static int ipmr_cache_report(struct net *net,
99 struct sk_buff *pkt, vifi_t vifi, int assert);
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000100static int ipmr_fill_mroute(struct net *net, struct sk_buff *skb,
101 struct mfc_cache *c, struct rtmsg *rtm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
104
Wang Chend6070322008-07-14 20:55:26 -0700105static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
106{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000107 struct net *net = dev_net(dev);
108
Wang Chend6070322008-07-14 20:55:26 -0700109 dev_close(dev);
110
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000111 dev = __dev_get_by_name(net, "tunl0");
Wang Chend6070322008-07-14 20:55:26 -0700112 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800113 const struct net_device_ops *ops = dev->netdev_ops;
Wang Chend6070322008-07-14 20:55:26 -0700114 struct ifreq ifr;
Wang Chend6070322008-07-14 20:55:26 -0700115 struct ip_tunnel_parm p;
116
117 memset(&p, 0, sizeof(p));
118 p.iph.daddr = v->vifc_rmt_addr.s_addr;
119 p.iph.saddr = v->vifc_lcl_addr.s_addr;
120 p.iph.version = 4;
121 p.iph.ihl = 5;
122 p.iph.protocol = IPPROTO_IPIP;
123 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
124 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
125
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800126 if (ops->ndo_do_ioctl) {
127 mm_segment_t oldfs = get_fs();
128
129 set_fs(KERNEL_DS);
130 ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
131 set_fs(oldfs);
132 }
Wang Chend6070322008-07-14 20:55:26 -0700133 }
134}
135
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000137struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
139 struct net_device *dev;
140
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000141 dev = __dev_get_by_name(net, "tunl0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800144 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 int err;
146 struct ifreq ifr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 struct ip_tunnel_parm p;
148 struct in_device *in_dev;
149
150 memset(&p, 0, sizeof(p));
151 p.iph.daddr = v->vifc_rmt_addr.s_addr;
152 p.iph.saddr = v->vifc_lcl_addr.s_addr;
153 p.iph.version = 4;
154 p.iph.ihl = 5;
155 p.iph.protocol = IPPROTO_IPIP;
156 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
Stephen Hemmingerba93ef72008-01-21 17:28:59 -0800157 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800159 if (ops->ndo_do_ioctl) {
160 mm_segment_t oldfs = get_fs();
161
162 set_fs(KERNEL_DS);
163 err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
164 set_fs(oldfs);
165 } else
166 err = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 dev = NULL;
169
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000170 if (err == 0 &&
171 (dev = __dev_get_by_name(net, p.name)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 dev->flags |= IFF_MULTICAST;
173
Herbert Xue5ed6392005-10-03 14:35:55 -0700174 in_dev = __in_dev_get_rtnl(dev);
Herbert Xu71e27da2007-06-04 23:36:06 -0700175 if (in_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700177
178 ipv4_devconf_setall(in_dev);
179 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 if (dev_open(dev))
182 goto failure;
Wang Chen7dc00c82008-07-14 20:56:34 -0700183 dev_hold(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 }
185 }
186 return dev;
187
188failure:
189 /* allow the register to be completed before unregistering. */
190 rtnl_unlock();
191 rtnl_lock();
192
193 unregister_netdevice(dev);
194 return NULL;
195}
196
197#ifdef CONFIG_IP_PIMSM
198
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000199static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000201 struct net *net = dev_net(dev);
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 read_lock(&mrt_lock);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700204 dev->stats.tx_bytes += skb->len;
205 dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000206 ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
207 IGMPMSG_WHOLEPKT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 read_unlock(&mrt_lock);
209 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000210 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
Stephen Hemminger007c3832008-11-20 20:28:35 -0800213static const struct net_device_ops reg_vif_netdev_ops = {
214 .ndo_start_xmit = reg_vif_xmit,
215};
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217static void reg_vif_setup(struct net_device *dev)
218{
219 dev->type = ARPHRD_PIMREG;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800220 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800222 dev->netdev_ops = &reg_vif_netdev_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700224 dev->features |= NETIF_F_NETNS_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
226
Tom Goff403dbb92009-06-14 03:16:13 -0700227static struct net_device *ipmr_reg_vif(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 struct net_device *dev;
230 struct in_device *in_dev;
231
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700232 dev = alloc_netdev(0, "pimreg", reg_vif_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 if (dev == NULL)
235 return NULL;
236
Tom Goff403dbb92009-06-14 03:16:13 -0700237 dev_net_set(dev, net);
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (register_netdevice(dev)) {
240 free_netdev(dev);
241 return NULL;
242 }
243 dev->iflink = 0;
244
Herbert Xu71e27da2007-06-04 23:36:06 -0700245 rcu_read_lock();
246 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
247 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Herbert Xu71e27da2007-06-04 23:36:06 -0700251 ipv4_devconf_setall(in_dev);
252 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
253 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 if (dev_open(dev))
256 goto failure;
257
Wang Chen7dc00c82008-07-14 20:56:34 -0700258 dev_hold(dev);
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 return dev;
261
262failure:
263 /* allow the register to be completed before unregistering. */
264 rtnl_unlock();
265 rtnl_lock();
266
267 unregister_netdevice(dev);
268 return NULL;
269}
270#endif
271
272/*
273 * Delete a VIF entry
Wang Chen7dc00c82008-07-14 20:56:34 -0700274 * @notify: Set to 1, if the caller is a notifier_call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900276
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000277static int vif_delete(struct net *net, int vifi, int notify,
278 struct list_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 struct vif_device *v;
281 struct net_device *dev;
282 struct in_device *in_dev;
283
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000284 if (vifi < 0 || vifi >= net->ipv4.maxvif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return -EADDRNOTAVAIL;
286
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000287 v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 write_lock_bh(&mrt_lock);
290 dev = v->dev;
291 v->dev = NULL;
292
293 if (!dev) {
294 write_unlock_bh(&mrt_lock);
295 return -EADDRNOTAVAIL;
296 }
297
298#ifdef CONFIG_IP_PIMSM
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000299 if (vifi == net->ipv4.mroute_reg_vif_num)
300 net->ipv4.mroute_reg_vif_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#endif
302
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000303 if (vifi+1 == net->ipv4.maxvif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 int tmp;
305 for (tmp=vifi-1; tmp>=0; tmp--) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000306 if (VIF_EXISTS(net, tmp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 break;
308 }
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000309 net->ipv4.maxvif = tmp+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311
312 write_unlock_bh(&mrt_lock);
313
314 dev_set_allmulti(dev, -1);
315
Herbert Xue5ed6392005-10-03 14:35:55 -0700316 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Herbert Xu42f811b2007-06-04 23:34:44 -0700317 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 ip_rt_multicast_event(in_dev);
319 }
320
Wang Chen7dc00c82008-07-14 20:56:34 -0700321 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000322 unregister_netdevice_queue(dev, head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 dev_put(dev);
325 return 0;
326}
327
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000328static inline void ipmr_cache_free(struct mfc_cache *c)
329{
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000330 kmem_cache_free(mrt_cachep, c);
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333/* Destroy an unresolved cache entry, killing queued skbs
334 and reporting error to netlink readers.
335 */
336
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000337static void ipmr_destroy_unres(struct net *net, struct mfc_cache *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700340 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000342 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Jianjun Kongc354e122008-11-03 00:28:02 -0800344 while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700345 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
347 nlh->nlmsg_type = NLMSG_ERROR;
348 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
349 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700350 e = NLMSG_DATA(nlh);
351 e->error = -ETIMEDOUT;
352 memset(&e->msg, 0, sizeof(e->msg));
Thomas Graf2942e902006-08-15 00:30:25 -0700353
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000354 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 } else
356 kfree_skb(skb);
357 }
358
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000359 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362
Patrick McHardye258beb2010-04-13 05:03:19 +0000363/* Timer process for the unresolved queue. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Patrick McHardye258beb2010-04-13 05:03:19 +0000365static void ipmr_expire_process(unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Patrick McHardye258beb2010-04-13 05:03:19 +0000367 struct net *net = (struct net *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 unsigned long now;
369 unsigned long expires;
370 struct mfc_cache *c, **cp;
371
372 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000373 mod_timer(&net->ipv4.ipmr_expire_timer, jiffies+HZ/10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return;
375 }
376
Patrick McHardye258beb2010-04-13 05:03:19 +0000377 if (net->ipv4.mfc_unres_queue == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto out;
379
380 now = jiffies;
381 expires = 10*HZ;
Patrick McHardye258beb2010-04-13 05:03:19 +0000382 cp = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 while ((c=*cp) != NULL) {
385 if (time_after(c->mfc_un.unres.expires, now)) {
386 unsigned long interval = c->mfc_un.unres.expires - now;
387 if (interval < expires)
388 expires = interval;
389 cp = &c->next;
390 continue;
391 }
392
393 *cp = c->next;
394
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000395 ipmr_destroy_unres(net, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
397
Patrick McHardye258beb2010-04-13 05:03:19 +0000398 if (net->ipv4.mfc_unres_queue != NULL)
399 mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401out:
402 spin_unlock(&mfc_unres_lock);
403}
404
405/* Fill oifs list. It is called under write locked mrt_lock. */
406
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000407static void ipmr_update_thresholds(struct net *net, struct mfc_cache *cache,
408 unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 int vifi;
411
412 cache->mfc_un.res.minvif = MAXVIFS;
413 cache->mfc_un.res.maxvif = 0;
414 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
415
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000416 for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
417 if (VIF_EXISTS(net, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000418 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
420 if (cache->mfc_un.res.minvif > vifi)
421 cache->mfc_un.res.minvif = vifi;
422 if (cache->mfc_un.res.maxvif <= vifi)
423 cache->mfc_un.res.maxvif = vifi + 1;
424 }
425 }
426}
427
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000428static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 int vifi = vifc->vifc_vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000431 struct vif_device *v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 struct net_device *dev;
433 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700434 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 /* Is vif busy ? */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000437 if (VIF_EXISTS(net, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return -EADDRINUSE;
439
440 switch (vifc->vifc_flags) {
441#ifdef CONFIG_IP_PIMSM
442 case VIFF_REGISTER:
443 /*
444 * Special Purpose VIF in PIM
445 * All the packets will be sent to the daemon
446 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000447 if (net->ipv4.mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return -EADDRINUSE;
Tom Goff403dbb92009-06-14 03:16:13 -0700449 dev = ipmr_reg_vif(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (!dev)
451 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700452 err = dev_set_allmulti(dev, 1);
453 if (err) {
454 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700455 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700456 return err;
457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 break;
459#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900460 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000461 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (!dev)
463 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700464 err = dev_set_allmulti(dev, 1);
465 if (err) {
466 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700467 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700468 return err;
469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 break;
Ilia Kee5e81f2009-09-16 05:53:07 +0000471
472 case VIFF_USE_IFINDEX:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 case 0:
Ilia Kee5e81f2009-09-16 05:53:07 +0000474 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
475 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
476 if (dev && dev->ip_ptr == NULL) {
477 dev_put(dev);
478 return -EADDRNOTAVAIL;
479 }
480 } else
481 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 if (!dev)
484 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700485 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700486 if (err) {
487 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700488 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 break;
491 default:
492 return -EINVAL;
493 }
494
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000495 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
496 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000498 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700499 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 ip_rt_multicast_event(in_dev);
501
502 /*
503 * Fill in the VIF structures
504 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800505 v->rate_limit = vifc->vifc_rate_limit;
506 v->local = vifc->vifc_lcl_addr.s_addr;
507 v->remote = vifc->vifc_rmt_addr.s_addr;
508 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (!mrtsock)
510 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800511 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 v->bytes_in = 0;
513 v->bytes_out = 0;
514 v->pkt_in = 0;
515 v->pkt_out = 0;
516 v->link = dev->ifindex;
517 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
518 v->link = dev->iflink;
519
520 /* And finish update writing critical data */
521 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800522 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523#ifdef CONFIG_IP_PIMSM
524 if (v->flags&VIFF_REGISTER)
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000525 net->ipv4.mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526#endif
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000527 if (vifi+1 > net->ipv4.maxvif)
528 net->ipv4.maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 write_unlock_bh(&mrt_lock);
530 return 0;
531}
532
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000533static struct mfc_cache *ipmr_cache_find(struct net *net,
534 __be32 origin,
535 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Jianjun Kongc354e122008-11-03 00:28:02 -0800537 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 struct mfc_cache *c;
539
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000540 for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
542 break;
543 }
544 return c;
545}
546
547/*
548 * Allocate a multicast cache entry
549 */
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000550static struct mfc_cache *ipmr_cache_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
Jianjun Kongc354e122008-11-03 00:28:02 -0800552 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
553 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 c->mfc_un.res.minvif = MAXVIFS;
556 return c;
557}
558
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000559static struct mfc_cache *ipmr_cache_alloc_unres(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
Jianjun Kongc354e122008-11-03 00:28:02 -0800561 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
562 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 skb_queue_head_init(&c->mfc_un.unres.unresolved);
565 c->mfc_un.unres.expires = jiffies + 10*HZ;
566 return c;
567}
568
569/*
570 * A cache entry has gone into a resolved state from queued
571 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900572
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000573static void ipmr_cache_resolve(struct net *net, struct mfc_cache *uc,
574 struct mfc_cache *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700577 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 /*
580 * Play the pending entries through our router
581 */
582
Jianjun Kongc354e122008-11-03 00:28:02 -0800583 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700584 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
586
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000587 if (ipmr_fill_mroute(net, skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700588 nlh->nlmsg_len = (skb_tail_pointer(skb) -
589 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 } else {
591 nlh->nlmsg_type = NLMSG_ERROR;
592 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
593 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700594 e = NLMSG_DATA(nlh);
595 e->error = -EMSGSIZE;
596 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
Thomas Graf2942e902006-08-15 00:30:25 -0700598
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000599 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 } else
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000601 ip_mr_forward(net, skb, c, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
603}
604
605/*
606 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
607 * expects the following bizarre scheme.
608 *
609 * Called under mrt_lock.
610 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900611
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000612static int ipmr_cache_report(struct net *net,
613 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
615 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300616 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 struct igmphdr *igmp;
618 struct igmpmsg *msg;
619 int ret;
620
621#ifdef CONFIG_IP_PIMSM
622 if (assert == IGMPMSG_WHOLEPKT)
623 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
624 else
625#endif
626 skb = alloc_skb(128, GFP_ATOMIC);
627
Stephen Hemminger132adf52007-03-08 20:44:43 -0800628 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return -ENOBUFS;
630
631#ifdef CONFIG_IP_PIMSM
632 if (assert == IGMPMSG_WHOLEPKT) {
633 /* Ugly, but we have no choice with this interface.
634 Duplicate old header, fix ihl, length etc.
635 And all this only to mangle msg->im_msgtype and
636 to set msg->im_mbz to "mbz" :-)
637 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300638 skb_push(skb, sizeof(struct iphdr));
639 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300640 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300641 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700642 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 msg->im_msgtype = IGMPMSG_WHOLEPKT;
644 msg->im_mbz = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000645 msg->im_vif = net->ipv4.mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700646 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
647 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
648 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900649 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900651 {
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 /*
654 * Copy the IP header
655 */
656
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700657 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300658 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300659 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700660 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
661 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000663 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 /*
666 * Add our header
667 */
668
Jianjun Kongc354e122008-11-03 00:28:02 -0800669 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 igmp->type =
671 msg->im_msgtype = assert;
672 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700673 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700674 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000677 if (net->ipv4.mroute_sk == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 kfree_skb(skb);
679 return -EINVAL;
680 }
681
682 /*
683 * Deliver to mrouted
684 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000685 ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
Benjamin Thery70a269e2009-01-22 04:56:15 +0000686 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 if (net_ratelimit())
688 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
689 kfree_skb(skb);
690 }
691
692 return ret;
693}
694
695/*
696 * Queue a packet for resolution. It gets locked cache entry!
697 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699static int
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000700ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
702 int err;
703 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700704 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000707 for (c=net->ipv4.mfc_unres_queue; c; c=c->next) {
708 if (c->mfc_mcastgrp == iph->daddr &&
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700709 c->mfc_origin == iph->saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 break;
711 }
712
713 if (c == NULL) {
714 /*
715 * Create a new entry if allowable
716 */
717
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000718 if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000719 (c = ipmr_cache_alloc_unres()) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 spin_unlock_bh(&mfc_unres_lock);
721
722 kfree_skb(skb);
723 return -ENOBUFS;
724 }
725
726 /*
727 * Fill in the new cache entry
728 */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700729 c->mfc_parent = -1;
730 c->mfc_origin = iph->saddr;
731 c->mfc_mcastgrp = iph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 /*
734 * Reflect first query at mrouted.
735 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000736 err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
737 if (err < 0) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900738 /* If the report failed throw the cache entry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 out - Brad Parker
740 */
741 spin_unlock_bh(&mfc_unres_lock);
742
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000743 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 kfree_skb(skb);
745 return err;
746 }
747
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000748 atomic_inc(&net->ipv4.cache_resolve_queue_len);
Patrick McHardye258beb2010-04-13 05:03:19 +0000749 c->next = net->ipv4.mfc_unres_queue;
750 net->ipv4.mfc_unres_queue = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Patrick McHardye258beb2010-04-13 05:03:19 +0000752 mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 }
754
755 /*
756 * See if we can append the packet
757 */
758 if (c->mfc_un.unres.unresolved.qlen>3) {
759 kfree_skb(skb);
760 err = -ENOBUFS;
761 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800762 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 err = 0;
764 }
765
766 spin_unlock_bh(&mfc_unres_lock);
767 return err;
768}
769
770/*
771 * MFC cache manipulation by user space mroute daemon
772 */
773
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000774static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 int line;
777 struct mfc_cache *c, **cp;
778
Jianjun Kongc354e122008-11-03 00:28:02 -0800779 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000781 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000782 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
784 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
785 write_lock_bh(&mrt_lock);
786 *cp = c->next;
787 write_unlock_bh(&mrt_lock);
788
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000789 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return 0;
791 }
792 }
793 return -ENOENT;
794}
795
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000796static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 int line;
799 struct mfc_cache *uc, *c, **cp;
800
Patrick McHardya50436f22010-03-17 06:04:14 +0000801 if (mfc->mfcc_parent >= MAXVIFS)
802 return -ENFILE;
803
Jianjun Kongc354e122008-11-03 00:28:02 -0800804 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000806 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000807 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
809 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
810 break;
811 }
812
813 if (c != NULL) {
814 write_lock_bh(&mrt_lock);
815 c->mfc_parent = mfc->mfcc_parent;
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000816 ipmr_update_thresholds(net, c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (!mrtsock)
818 c->mfc_flags |= MFC_STATIC;
819 write_unlock_bh(&mrt_lock);
820 return 0;
821 }
822
Joe Perchesf97c1e02007-12-16 13:45:43 -0800823 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return -EINVAL;
825
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000826 c = ipmr_cache_alloc();
Jianjun Kongc354e122008-11-03 00:28:02 -0800827 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return -ENOMEM;
829
Jianjun Kongc354e122008-11-03 00:28:02 -0800830 c->mfc_origin = mfc->mfcc_origin.s_addr;
831 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
832 c->mfc_parent = mfc->mfcc_parent;
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000833 ipmr_update_thresholds(net, c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 if (!mrtsock)
835 c->mfc_flags |= MFC_STATIC;
836
837 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000838 c->next = net->ipv4.mfc_cache_array[line];
839 net->ipv4.mfc_cache_array[line] = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 write_unlock_bh(&mrt_lock);
841
842 /*
843 * Check to see if we resolved a queued list. If so we
844 * need to send on the frames and tidy up.
845 */
846 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000847 for (cp = &net->ipv4.mfc_unres_queue; (uc=*cp) != NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 cp = &uc->next) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000849 if (uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
851 *cp = uc->next;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000852 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 break;
854 }
855 }
Patrick McHardye258beb2010-04-13 05:03:19 +0000856 if (net->ipv4.mfc_unres_queue == NULL)
857 del_timer(&net->ipv4.ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 spin_unlock_bh(&mfc_unres_lock);
859
860 if (uc) {
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000861 ipmr_cache_resolve(net, uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000862 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
864 return 0;
865}
866
867/*
868 * Close the multicast socket, and clear the vif tables etc
869 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900870
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000871static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000874 LIST_HEAD(list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 /*
877 * Shut down all active vif entries
878 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000879 for (i = 0; i < net->ipv4.maxvif; i++) {
880 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000881 vif_delete(net, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000883 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 /*
886 * Wipe the cache
887 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800888 for (i=0; i<MFC_LINES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 struct mfc_cache *c, **cp;
890
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000891 cp = &net->ipv4.mfc_cache_array[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 while ((c = *cp) != NULL) {
893 if (c->mfc_flags&MFC_STATIC) {
894 cp = &c->next;
895 continue;
896 }
897 write_lock_bh(&mrt_lock);
898 *cp = c->next;
899 write_unlock_bh(&mrt_lock);
900
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000901 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 }
904
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000905 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000906 struct mfc_cache *c, **cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000909 cp = &net->ipv4.mfc_unres_queue;
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000910 while ((c = *cp) != NULL) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000911 *cp = c->next;
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000912 ipmr_destroy_unres(net, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
914 spin_unlock_bh(&mfc_unres_lock);
915 }
916}
917
918static void mrtsock_destruct(struct sock *sk)
919{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000920 struct net *net = sock_net(sk);
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000923 if (sk == net->ipv4.mroute_sk) {
924 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000927 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 write_unlock_bh(&mrt_lock);
929
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000930 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
932 rtnl_unlock();
933}
934
935/*
936 * Socket options and virtual interface manipulation. The whole
937 * virtual interface system is a complete heap, but unfortunately
938 * that's how BSD mrouted happens to think. Maybe one day with a proper
939 * MOSPF/PIM router set up we can clean this up.
940 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900941
David S. Millerb7058842009-09-30 16:12:20 -0700942int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 int ret;
945 struct vifctl vif;
946 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000947 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900948
Stephen Hemminger132adf52007-03-08 20:44:43 -0800949 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000950 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return -EACCES;
952 }
953
Stephen Hemminger132adf52007-03-08 20:44:43 -0800954 switch (optname) {
955 case MRT_INIT:
956 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000957 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800958 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800959 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800960 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Stephen Hemminger132adf52007-03-08 20:44:43 -0800962 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000963 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800965 return -EADDRINUSE;
966 }
967
968 ret = ip_ra_control(sk, 1, mrtsock_destruct);
969 if (ret == 0) {
970 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000971 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800972 write_unlock_bh(&mrt_lock);
973
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000974 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800975 }
976 rtnl_unlock();
977 return ret;
978 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000979 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800980 return -EACCES;
981 return ip_ra_control(sk, 0, NULL);
982 case MRT_ADD_VIF:
983 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800984 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800985 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800986 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800987 return -EFAULT;
988 if (vif.vifc_vifi >= MAXVIFS)
989 return -ENFILE;
990 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -0800991 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000992 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800993 } else {
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000994 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800995 }
996 rtnl_unlock();
997 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
999 /*
1000 * Manipulate the forwarding caches. These live
1001 * in a sort of kernel/user symbiosis.
1002 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001003 case MRT_ADD_MFC:
1004 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -08001005 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001006 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001007 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001008 return -EFAULT;
1009 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001010 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001011 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001012 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001013 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001014 rtnl_unlock();
1015 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /*
1017 * Control PIM assert.
1018 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001019 case MRT_ASSERT:
1020 {
1021 int v;
1022 if (get_user(v,(int __user *)optval))
1023 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001024 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001025 return 0;
1026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001028 case MRT_PIM:
1029 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001030 int v;
1031
Stephen Hemminger132adf52007-03-08 20:44:43 -08001032 if (get_user(v,(int __user *)optval))
1033 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001034 v = (v) ? 1 : 0;
1035
Stephen Hemminger132adf52007-03-08 20:44:43 -08001036 rtnl_lock();
1037 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001038 if (v != net->ipv4.mroute_do_pim) {
1039 net->ipv4.mroute_do_pim = v;
1040 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001042 rtnl_unlock();
1043 return ret;
1044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001046 /*
1047 * Spurious command, or MRT_VERSION which you cannot
1048 * set.
1049 */
1050 default:
1051 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
1053}
1054
1055/*
1056 * Getsock opt support for the multicast routing system.
1057 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001058
Jianjun Kongc354e122008-11-03 00:28:02 -08001059int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060{
1061 int olr;
1062 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001063 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Jianjun Kongc354e122008-11-03 00:28:02 -08001065 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066#ifdef CONFIG_IP_PIMSM
1067 optname!=MRT_PIM &&
1068#endif
1069 optname!=MRT_ASSERT)
1070 return -ENOPROTOOPT;
1071
1072 if (get_user(olr, optlen))
1073 return -EFAULT;
1074
1075 olr = min_t(unsigned int, olr, sizeof(int));
1076 if (olr < 0)
1077 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001078
Jianjun Kongc354e122008-11-03 00:28:02 -08001079 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001081 if (optname == MRT_VERSION)
1082 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001084 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001085 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086#endif
1087 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001088 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001089 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 return -EFAULT;
1091 return 0;
1092}
1093
1094/*
1095 * The IP multicast ioctl support routines.
1096 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1099{
1100 struct sioc_sg_req sr;
1101 struct sioc_vif_req vr;
1102 struct vif_device *vif;
1103 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001104 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001105
Stephen Hemminger132adf52007-03-08 20:44:43 -08001106 switch (cmd) {
1107 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001108 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001109 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001110 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001111 return -EINVAL;
1112 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001113 vif = &net->ipv4.vif_table[vr.vifi];
1114 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001115 vr.icount = vif->pkt_in;
1116 vr.ocount = vif->pkt_out;
1117 vr.ibytes = vif->bytes_in;
1118 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001120
Jianjun Kongc354e122008-11-03 00:28:02 -08001121 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001123 return 0;
1124 }
1125 read_unlock(&mrt_lock);
1126 return -EADDRNOTAVAIL;
1127 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001128 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001129 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Stephen Hemminger132adf52007-03-08 20:44:43 -08001131 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001132 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001133 if (c) {
1134 sr.pktcnt = c->mfc_un.res.pkt;
1135 sr.bytecnt = c->mfc_un.res.bytes;
1136 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001138
Jianjun Kongc354e122008-11-03 00:28:02 -08001139 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001140 return -EFAULT;
1141 return 0;
1142 }
1143 read_unlock(&mrt_lock);
1144 return -EADDRNOTAVAIL;
1145 default:
1146 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148}
1149
1150
1151static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1152{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001153 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001154 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 struct vif_device *v;
1156 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001157 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001158
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 if (event != NETDEV_UNREGISTER)
1160 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001161 v = &net->ipv4.vif_table[0];
1162 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001163 if (v->dev == dev)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001164 vif_delete(net, ct, 1, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001166 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return NOTIFY_DONE;
1168}
1169
1170
Jianjun Kongc354e122008-11-03 00:28:02 -08001171static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 .notifier_call = ipmr_device_event,
1173};
1174
1175/*
1176 * Encapsulate a packet by attaching a valid IPIP header to it.
1177 * This avoids tunnel drivers and other mess and gives us the speed so
1178 * important for multicast video.
1179 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001180
Al Viro114c7842006-09-27 18:39:29 -07001181static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001183 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001184 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001185
1186 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001187 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001188 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001189 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001192 iph->tos = old_iph->tos;
1193 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 iph->frag_off = 0;
1195 iph->daddr = daddr;
1196 iph->saddr = saddr;
1197 iph->protocol = IPPROTO_IPIP;
1198 iph->ihl = 5;
1199 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001200 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 ip_send_check(iph);
1202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1204 nf_reset(skb);
1205}
1206
1207static inline int ipmr_forward_finish(struct sk_buff *skb)
1208{
1209 struct ip_options * opt = &(IPCB(skb)->opt);
1210
Eric Dumazetadf30902009-06-02 05:19:30 +00001211 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 if (unlikely(opt->optlen))
1214 ip_forward_options(skb);
1215
1216 return dst_output(skb);
1217}
1218
1219/*
1220 * Processing handlers for ipmr_forward
1221 */
1222
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001223static void ipmr_queue_xmit(struct net *net, struct sk_buff *skb,
1224 struct mfc_cache *c, int vifi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001226 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001227 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 struct net_device *dev;
1229 struct rtable *rt;
1230 int encap = 0;
1231
1232 if (vif->dev == NULL)
1233 goto out_free;
1234
1235#ifdef CONFIG_IP_PIMSM
1236 if (vif->flags & VIFF_REGISTER) {
1237 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001238 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001239 vif->dev->stats.tx_bytes += skb->len;
1240 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001241 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001242 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
1244#endif
1245
1246 if (vif->flags&VIFF_TUNNEL) {
1247 struct flowi fl = { .oif = vif->link,
1248 .nl_u = { .ip4_u =
1249 { .daddr = vif->remote,
1250 .saddr = vif->local,
1251 .tos = RT_TOS(iph->tos) } },
1252 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001253 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 goto out_free;
1255 encap = sizeof(struct iphdr);
1256 } else {
1257 struct flowi fl = { .oif = vif->link,
1258 .nl_u = { .ip4_u =
1259 { .daddr = iph->daddr,
1260 .tos = RT_TOS(iph->tos) } },
1261 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001262 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 goto out_free;
1264 }
1265
1266 dev = rt->u.dst.dev;
1267
1268 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1269 /* Do not fragment multicasts. Alas, IPv4 does not
1270 allow to send ICMP, so that packets will disappear
1271 to blackhole.
1272 */
1273
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001274 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 ip_rt_put(rt);
1276 goto out_free;
1277 }
1278
1279 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1280
1281 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001282 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 goto out_free;
1284 }
1285
1286 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001287 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Eric Dumazetadf30902009-06-02 05:19:30 +00001289 skb_dst_drop(skb);
1290 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001291 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
1293 /* FIXME: forward and output firewalls used to be called here.
1294 * What do we do with netfilter? -- RR */
1295 if (vif->flags & VIFF_TUNNEL) {
1296 ip_encap(skb, vif->local, vif->remote);
1297 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001298 vif->dev->stats.tx_packets++;
1299 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 }
1301
1302 IPCB(skb)->flags |= IPSKB_FORWARDED;
1303
1304 /*
1305 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1306 * not only before forwarding, but after forwarding on all output
1307 * interfaces. It is clear, if mrouter runs a multicasting
1308 * program, it should receive packets not depending to what interface
1309 * program is joined.
1310 * If we will not make it, the program will have to join on all
1311 * interfaces. On the other hand, multihoming host (or router, but
1312 * not mrouter) cannot join to more than one interface - it will
1313 * result in receiving multiple packets.
1314 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001315 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 ipmr_forward_finish);
1317 return;
1318
1319out_free:
1320 kfree_skb(skb);
1321 return;
1322}
1323
1324static int ipmr_find_vif(struct net_device *dev)
1325{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001326 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001328 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1329 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 break;
1331 }
1332 return ct;
1333}
1334
1335/* "local" means that we should preserve one skb (for local delivery) */
1336
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001337static int ip_mr_forward(struct net *net, struct sk_buff *skb,
1338 struct mfc_cache *cache, int local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339{
1340 int psend = -1;
1341 int vif, ct;
1342
1343 vif = cache->mfc_parent;
1344 cache->mfc_un.res.pkt++;
1345 cache->mfc_un.res.bytes += skb->len;
1346
1347 /*
1348 * Wrong interface: drop packet and (maybe) send PIM assert.
1349 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001350 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 int true_vifi;
1352
Eric Dumazet511c3f92009-06-02 05:14:27 +00001353 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 /* It is our own packet, looped back.
1355 Very complicated situation...
1356
1357 The best workaround until routing daemons will be
1358 fixed is not to redistribute packet, if it was
1359 send through wrong interface. It means, that
1360 multicast applications WILL NOT work for
1361 (S,G), which have default multicast route pointing
1362 to wrong oif. In any case, it is not a good
1363 idea to use multicasting applications on router.
1364 */
1365 goto dont_forward;
1366 }
1367
1368 cache->mfc_un.res.wrong_if++;
1369 true_vifi = ipmr_find_vif(skb->dev);
1370
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001371 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 /* pimsm uses asserts, when switching from RPT to SPT,
1373 so that we cannot check that packet arrived on an oif.
1374 It is bad, but otherwise we would need to move pretty
1375 large chunk of pimd to kernel. Ough... --ANK
1376 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001377 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001378 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001379 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1381 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001382 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 }
1384 goto dont_forward;
1385 }
1386
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001387 net->ipv4.vif_table[vif].pkt_in++;
1388 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 /*
1391 * Forward the frame
1392 */
1393 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001394 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if (psend != -1) {
1396 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1397 if (skb2)
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001398 ipmr_queue_xmit(net, skb2, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001400 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
1402 }
1403 if (psend != -1) {
1404 if (local) {
1405 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1406 if (skb2)
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001407 ipmr_queue_xmit(net, skb2, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 } else {
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001409 ipmr_queue_xmit(net, skb, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 return 0;
1411 }
1412 }
1413
1414dont_forward:
1415 if (!local)
1416 kfree_skb(skb);
1417 return 0;
1418}
1419
1420
1421/*
1422 * Multicast packets for forwarding arrive here
1423 */
1424
1425int ip_mr_input(struct sk_buff *skb)
1426{
1427 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001428 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001429 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 /* Packet is looped back after forward, it should not be
1432 forwarded second time, but still can be delivered locally.
1433 */
1434 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1435 goto dont_forward;
1436
1437 if (!local) {
1438 if (IPCB(skb)->opt.router_alert) {
1439 if (ip_call_ra_chain(skb))
1440 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001441 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 /* IGMPv1 (and broken IGMPv2 implementations sort of
1443 Cisco IOS <= 11.2(8)) do not put router alert
1444 option to IGMP packets destined to routable
1445 groups. It is very bad, because it means
1446 that we can forward NO IGMP messages.
1447 */
1448 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001449 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001450 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001451 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 read_unlock(&mrt_lock);
1453 return 0;
1454 }
1455 read_unlock(&mrt_lock);
1456 }
1457 }
1458
1459 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001460 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 /*
1463 * No usable cache entry
1464 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001465 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 int vif;
1467
1468 if (local) {
1469 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1470 ip_local_deliver(skb);
1471 if (skb2 == NULL) {
1472 read_unlock(&mrt_lock);
1473 return -ENOBUFS;
1474 }
1475 skb = skb2;
1476 }
1477
1478 vif = ipmr_find_vif(skb->dev);
1479 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001480 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 read_unlock(&mrt_lock);
1482
1483 return err;
1484 }
1485 read_unlock(&mrt_lock);
1486 kfree_skb(skb);
1487 return -ENODEV;
1488 }
1489
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001490 ip_mr_forward(net, skb, cache, local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
1492 read_unlock(&mrt_lock);
1493
1494 if (local)
1495 return ip_local_deliver(skb);
1496
1497 return 0;
1498
1499dont_forward:
1500 if (local)
1501 return ip_local_deliver(skb);
1502 kfree_skb(skb);
1503 return 0;
1504}
1505
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001506#ifdef CONFIG_IP_PIMSM
1507static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001509 struct net_device *reg_dev = NULL;
1510 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001511 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001513 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 /*
1515 Check that:
1516 a. packet is really destinted to a multicast group
1517 b. packet is not a NULL-REGISTER
1518 c. packet is not truncated
1519 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001520 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001522 ntohs(encap->tot_len) + pimlen > skb->len)
1523 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001526 if (net->ipv4.mroute_reg_vif_num >= 0)
1527 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 if (reg_dev)
1529 dev_hold(reg_dev);
1530 read_unlock(&mrt_lock);
1531
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001532 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001533 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001535 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001537 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 skb->protocol = htons(ETH_P_IP);
1540 skb->ip_summed = 0;
1541 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001542 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001543 reg_dev->stats.rx_bytes += skb->len;
1544 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 nf_reset(skb);
1546 netif_rx(skb);
1547 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001550}
1551#endif
1552
1553#ifdef CONFIG_IP_PIMSM_V1
1554/*
1555 * Handle IGMP messages of PIMv1
1556 */
1557
1558int pim_rcv_v1(struct sk_buff * skb)
1559{
1560 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001561 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001562
1563 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1564 goto drop;
1565
1566 pim = igmp_hdr(skb);
1567
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001568 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001569 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1570 goto drop;
1571
1572 if (__pim_rcv(skb, sizeof(*pim))) {
1573drop:
1574 kfree_skb(skb);
1575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 return 0;
1577}
1578#endif
1579
1580#ifdef CONFIG_IP_PIMSM_V2
1581static int pim_rcv(struct sk_buff * skb)
1582{
1583 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001585 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 goto drop;
1587
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001588 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001589 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001591 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001592 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 goto drop;
1594
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001595 if (__pim_rcv(skb, sizeof(*pim))) {
1596drop:
1597 kfree_skb(skb);
1598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 return 0;
1600}
1601#endif
1602
1603static int
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001604ipmr_fill_mroute(struct net *net, struct sk_buff *skb, struct mfc_cache *c,
1605 struct rtmsg *rtm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606{
1607 int ct;
1608 struct rtnexthop *nhp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001609 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 struct rtattr *mp_head;
1611
Nicolas Dichtel74381892010-03-25 23:45:35 +00001612 /* If cache is unresolved, don't try to parse IIF and OIF */
1613 if (c->mfc_parent > MAXVIFS)
1614 return -ENOENT;
1615
1616 if (VIF_EXISTS(net, c->mfc_parent))
1617 RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Jianjun Kongc354e122008-11-03 00:28:02 -08001619 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
1621 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Nicolas Dichtel74381892010-03-25 23:45:35 +00001622 if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1624 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001625 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 nhp->rtnh_flags = 0;
1627 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001628 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 nhp->rtnh_len = sizeof(*nhp);
1630 }
1631 }
1632 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001633 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 rtm->rtm_type = RTN_MULTICAST;
1635 return 1;
1636
1637rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001638 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 return -EMSGSIZE;
1640}
1641
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001642int ipmr_get_route(struct net *net,
1643 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
1645 int err;
1646 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001647 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001650 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Jianjun Kongc354e122008-11-03 00:28:02 -08001652 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001653 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001654 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 struct net_device *dev;
1656 int vif;
1657
1658 if (nowait) {
1659 read_unlock(&mrt_lock);
1660 return -EAGAIN;
1661 }
1662
1663 dev = skb->dev;
1664 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1665 read_unlock(&mrt_lock);
1666 return -ENODEV;
1667 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001668 skb2 = skb_clone(skb, GFP_ATOMIC);
1669 if (!skb2) {
1670 read_unlock(&mrt_lock);
1671 return -ENOMEM;
1672 }
1673
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001674 skb_push(skb2, sizeof(struct iphdr));
1675 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001676 iph = ip_hdr(skb2);
1677 iph->ihl = sizeof(struct iphdr) >> 2;
1678 iph->saddr = rt->rt_src;
1679 iph->daddr = rt->rt_dst;
1680 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001681 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 read_unlock(&mrt_lock);
1683 return err;
1684 }
1685
1686 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1687 cache->mfc_flags |= MFC_NOTIFY;
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001688 err = ipmr_fill_mroute(net, skb, cache, rtm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 read_unlock(&mrt_lock);
1690 return err;
1691}
1692
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001693#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694/*
1695 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1696 */
1697struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001698 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 int ct;
1700};
1701
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001702static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1703 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 loff_t pos)
1705{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001706 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1707 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001709 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001710 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 }
1712 return NULL;
1713}
1714
1715static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001716 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001718 struct net *net = seq_file_net(seq);
1719
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001721 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 : SEQ_START_TOKEN;
1723}
1724
1725static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1726{
1727 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001728 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730 ++*pos;
1731 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001732 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001733
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001734 while (++iter->ct < net->ipv4.maxvif) {
1735 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001737 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 }
1739 return NULL;
1740}
1741
1742static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001743 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744{
1745 read_unlock(&mrt_lock);
1746}
1747
1748static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1749{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001750 struct net *net = seq_file_net(seq);
1751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001753 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1755 } else {
1756 const struct vif_device *vif = v;
1757 const char *name = vif->dev ? vif->dev->name : "none";
1758
1759 seq_printf(seq,
1760 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001761 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001762 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 vif->bytes_out, vif->pkt_out,
1764 vif->flags, vif->local, vif->remote);
1765 }
1766 return 0;
1767}
1768
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001769static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 .start = ipmr_vif_seq_start,
1771 .next = ipmr_vif_seq_next,
1772 .stop = ipmr_vif_seq_stop,
1773 .show = ipmr_vif_seq_show,
1774};
1775
1776static int ipmr_vif_open(struct inode *inode, struct file *file)
1777{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001778 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1779 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780}
1781
Arjan van de Ven9a321442007-02-12 00:55:35 -08001782static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 .owner = THIS_MODULE,
1784 .open = ipmr_vif_open,
1785 .read = seq_read,
1786 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001787 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788};
1789
1790struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001791 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 struct mfc_cache **cache;
1793 int ct;
1794};
1795
1796
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001797static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1798 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799{
1800 struct mfc_cache *mfc;
1801
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001802 it->cache = net->ipv4.mfc_cache_array;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 read_lock(&mrt_lock);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001804 for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001805 for (mfc = net->ipv4.mfc_cache_array[it->ct];
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001806 mfc; mfc = mfc->next)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001807 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 return mfc;
1809 read_unlock(&mrt_lock);
1810
Patrick McHardye258beb2010-04-13 05:03:19 +00001811 it->cache = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001813 for (mfc = net->ipv4.mfc_unres_queue; mfc; mfc = mfc->next)
1814 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 return mfc;
1816 spin_unlock_bh(&mfc_unres_lock);
1817
1818 it->cache = NULL;
1819 return NULL;
1820}
1821
1822
1823static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1824{
1825 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001826 struct net *net = seq_file_net(seq);
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 it->cache = NULL;
1829 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001830 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 : SEQ_START_TOKEN;
1832}
1833
1834static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1835{
1836 struct mfc_cache *mfc = v;
1837 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001838 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
1840 ++*pos;
1841
1842 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001843 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 if (mfc->next)
1846 return mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001847
Patrick McHardye258beb2010-04-13 05:03:19 +00001848 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 goto end_of_list;
1850
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001851 BUG_ON(it->cache != net->ipv4.mfc_cache_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 while (++it->ct < MFC_LINES) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001854 mfc = net->ipv4.mfc_cache_array[it->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if (mfc)
1856 return mfc;
1857 }
1858
1859 /* exhausted cache_array, show unresolved */
1860 read_unlock(&mrt_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001861 it->cache = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001863
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001865 mfc = net->ipv4.mfc_unres_queue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001866 if (mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return mfc;
1868
1869 end_of_list:
1870 spin_unlock_bh(&mfc_unres_lock);
1871 it->cache = NULL;
1872
1873 return NULL;
1874}
1875
1876static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1877{
1878 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001879 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Patrick McHardye258beb2010-04-13 05:03:19 +00001881 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 spin_unlock_bh(&mfc_unres_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001883 else if (it->cache == net->ipv4.mfc_cache_array)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 read_unlock(&mrt_lock);
1885}
1886
1887static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1888{
1889 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001890 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
1892 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001893 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1895 } else {
1896 const struct mfc_cache *mfc = v;
1897 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001898
Benjamin Thery999890b2008-12-03 22:22:16 -08001899 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 (unsigned long) mfc->mfc_mcastgrp,
1901 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001902 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
Patrick McHardye258beb2010-04-13 05:03:19 +00001904 if (it->cache != &net->ipv4.mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001905 seq_printf(seq, " %8lu %8lu %8lu",
1906 mfc->mfc_un.res.pkt,
1907 mfc->mfc_un.res.bytes,
1908 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001909 for (n = mfc->mfc_un.res.minvif;
1910 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001911 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001912 mfc->mfc_un.res.ttls[n] < 255)
1913 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001914 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 n, mfc->mfc_un.res.ttls[n]);
1916 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001917 } else {
1918 /* unresolved mfc_caches don't contain
1919 * pkt, bytes and wrong_if values
1920 */
1921 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923 seq_putc(seq, '\n');
1924 }
1925 return 0;
1926}
1927
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001928static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 .start = ipmr_mfc_seq_start,
1930 .next = ipmr_mfc_seq_next,
1931 .stop = ipmr_mfc_seq_stop,
1932 .show = ipmr_mfc_seq_show,
1933};
1934
1935static int ipmr_mfc_open(struct inode *inode, struct file *file)
1936{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001937 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1938 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939}
1940
Arjan van de Ven9a321442007-02-12 00:55:35 -08001941static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 .owner = THIS_MODULE,
1943 .open = ipmr_mfc_open,
1944 .read = seq_read,
1945 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001946 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001948#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
1950#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001951static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001953 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954};
1955#endif
1956
1957
1958/*
1959 * Setup for IP multicast routing
1960 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001961static int __net_init ipmr_net_init(struct net *net)
1962{
1963 int err = 0;
1964
1965 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1966 GFP_KERNEL);
1967 if (!net->ipv4.vif_table) {
1968 err = -ENOMEM;
1969 goto fail;
1970 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001971
1972 /* Forwarding cache */
1973 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
1974 sizeof(struct mfc_cache *),
1975 GFP_KERNEL);
1976 if (!net->ipv4.mfc_cache_array) {
1977 err = -ENOMEM;
1978 goto fail_mfc_cache;
1979 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001980
Patrick McHardye258beb2010-04-13 05:03:19 +00001981 setup_timer(&net->ipv4.ipmr_expire_timer, ipmr_expire_process,
1982 (unsigned long)net);
1983
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001984#ifdef CONFIG_IP_PIMSM
1985 net->ipv4.mroute_reg_vif_num = -1;
1986#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001987
1988#ifdef CONFIG_PROC_FS
1989 err = -ENOMEM;
1990 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
1991 goto proc_vif_fail;
1992 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
1993 goto proc_cache_fail;
1994#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001995 return 0;
1996
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001997#ifdef CONFIG_PROC_FS
1998proc_cache_fail:
1999 proc_net_remove(net, "ip_mr_vif");
2000proc_vif_fail:
2001 kfree(net->ipv4.mfc_cache_array);
2002#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002003fail_mfc_cache:
2004 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002005fail:
2006 return err;
2007}
2008
2009static void __net_exit ipmr_net_exit(struct net *net)
2010{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002011#ifdef CONFIG_PROC_FS
2012 proc_net_remove(net, "ip_mr_cache");
2013 proc_net_remove(net, "ip_mr_vif");
2014#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002015 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002016 kfree(net->ipv4.vif_table);
2017}
2018
2019static struct pernet_operations ipmr_net_ops = {
2020 .init = ipmr_net_init,
2021 .exit = ipmr_net_exit,
2022};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002023
Wang Chen03d2f892008-07-03 12:13:36 +08002024int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025{
Wang Chen03d2f892008-07-03 12:13:36 +08002026 int err;
2027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2029 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002030 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002031 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002032 if (!mrt_cachep)
2033 return -ENOMEM;
2034
Benjamin Therycf958ae32009-01-22 04:56:16 +00002035 err = register_pernet_subsys(&ipmr_net_ops);
2036 if (err)
2037 goto reg_pernet_fail;
2038
Wang Chen03d2f892008-07-03 12:13:36 +08002039 err = register_netdevice_notifier(&ip_mr_notifier);
2040 if (err)
2041 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002042#ifdef CONFIG_IP_PIMSM_V2
2043 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2044 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2045 err = -EAGAIN;
2046 goto add_proto_fail;
2047 }
2048#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002049 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002050
Tom Goff403dbb92009-06-14 03:16:13 -07002051#ifdef CONFIG_IP_PIMSM_V2
2052add_proto_fail:
2053 unregister_netdevice_notifier(&ip_mr_notifier);
2054#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002055reg_notif_fail:
Benjamin Therycf958ae32009-01-22 04:56:16 +00002056 unregister_pernet_subsys(&ipmr_net_ops);
2057reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002058 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002059 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060}