blob: 21b5edc2f343c01d5bf7587e4f79c08f42ed254b [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;
Patrick McHardy862465f2010-04-13 05:03:21 +0000370 struct mfc_cache *c, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
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 McHardy862465f2010-04-13 05:03:21 +0000377 if (list_empty(&net->ipv4.mfc_unres_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto out;
379
380 now = jiffies;
381 expires = 10*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Patrick McHardy862465f2010-04-13 05:03:21 +0000383 list_for_each_entry_safe(c, next, &net->ipv4.mfc_unres_queue, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 if (time_after(c->mfc_un.unres.expires, now)) {
385 unsigned long interval = c->mfc_un.unres.expires - now;
386 if (interval < expires)
387 expires = interval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 continue;
389 }
390
Patrick McHardy862465f2010-04-13 05:03:21 +0000391 list_del(&c->list);
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000392 ipmr_destroy_unres(net, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 }
394
Patrick McHardy862465f2010-04-13 05:03:21 +0000395 if (!list_empty(&net->ipv4.mfc_unres_queue))
Patrick McHardye258beb2010-04-13 05:03:19 +0000396 mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398out:
399 spin_unlock(&mfc_unres_lock);
400}
401
402/* Fill oifs list. It is called under write locked mrt_lock. */
403
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000404static void ipmr_update_thresholds(struct net *net, struct mfc_cache *cache,
405 unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 int vifi;
408
409 cache->mfc_un.res.minvif = MAXVIFS;
410 cache->mfc_un.res.maxvif = 0;
411 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
412
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000413 for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
414 if (VIF_EXISTS(net, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000415 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
417 if (cache->mfc_un.res.minvif > vifi)
418 cache->mfc_un.res.minvif = vifi;
419 if (cache->mfc_un.res.maxvif <= vifi)
420 cache->mfc_un.res.maxvif = vifi + 1;
421 }
422 }
423}
424
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000425static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
427 int vifi = vifc->vifc_vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000428 struct vif_device *v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 struct net_device *dev;
430 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700431 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 /* Is vif busy ? */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000434 if (VIF_EXISTS(net, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return -EADDRINUSE;
436
437 switch (vifc->vifc_flags) {
438#ifdef CONFIG_IP_PIMSM
439 case VIFF_REGISTER:
440 /*
441 * Special Purpose VIF in PIM
442 * All the packets will be sent to the daemon
443 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000444 if (net->ipv4.mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return -EADDRINUSE;
Tom Goff403dbb92009-06-14 03:16:13 -0700446 dev = ipmr_reg_vif(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 if (!dev)
448 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700449 err = dev_set_allmulti(dev, 1);
450 if (err) {
451 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700452 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700453 return err;
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 break;
456#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900457 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000458 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 if (!dev)
460 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700461 err = dev_set_allmulti(dev, 1);
462 if (err) {
463 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700464 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700465 return err;
466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 break;
Ilia Kee5e81f2009-09-16 05:53:07 +0000468
469 case VIFF_USE_IFINDEX:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 case 0:
Ilia Kee5e81f2009-09-16 05:53:07 +0000471 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
472 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
473 if (dev && dev->ip_ptr == NULL) {
474 dev_put(dev);
475 return -EADDRNOTAVAIL;
476 }
477 } else
478 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 if (!dev)
481 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700482 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700483 if (err) {
484 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700485 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 break;
488 default:
489 return -EINVAL;
490 }
491
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000492 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
493 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000495 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700496 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 ip_rt_multicast_event(in_dev);
498
499 /*
500 * Fill in the VIF structures
501 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800502 v->rate_limit = vifc->vifc_rate_limit;
503 v->local = vifc->vifc_lcl_addr.s_addr;
504 v->remote = vifc->vifc_rmt_addr.s_addr;
505 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if (!mrtsock)
507 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800508 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 v->bytes_in = 0;
510 v->bytes_out = 0;
511 v->pkt_in = 0;
512 v->pkt_out = 0;
513 v->link = dev->ifindex;
514 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
515 v->link = dev->iflink;
516
517 /* And finish update writing critical data */
518 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800519 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520#ifdef CONFIG_IP_PIMSM
521 if (v->flags&VIFF_REGISTER)
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000522 net->ipv4.mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523#endif
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000524 if (vifi+1 > net->ipv4.maxvif)
525 net->ipv4.maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 write_unlock_bh(&mrt_lock);
527 return 0;
528}
529
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000530static struct mfc_cache *ipmr_cache_find(struct net *net,
531 __be32 origin,
532 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533{
Jianjun Kongc354e122008-11-03 00:28:02 -0800534 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 struct mfc_cache *c;
536
Patrick McHardy862465f2010-04-13 05:03:21 +0000537 list_for_each_entry(c, &net->ipv4.mfc_cache_array[line], list) {
538 if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
539 return c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
Patrick McHardy862465f2010-04-13 05:03:21 +0000541 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542}
543
544/*
545 * Allocate a multicast cache entry
546 */
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000547static struct mfc_cache *ipmr_cache_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
Jianjun Kongc354e122008-11-03 00:28:02 -0800549 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
550 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 c->mfc_un.res.minvif = MAXVIFS;
553 return c;
554}
555
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000556static struct mfc_cache *ipmr_cache_alloc_unres(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
Jianjun Kongc354e122008-11-03 00:28:02 -0800558 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
559 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 skb_queue_head_init(&c->mfc_un.unres.unresolved);
562 c->mfc_un.unres.expires = jiffies + 10*HZ;
563 return c;
564}
565
566/*
567 * A cache entry has gone into a resolved state from queued
568 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900569
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000570static void ipmr_cache_resolve(struct net *net, struct mfc_cache *uc,
571 struct mfc_cache *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572{
573 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700574 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 /*
577 * Play the pending entries through our router
578 */
579
Jianjun Kongc354e122008-11-03 00:28:02 -0800580 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700581 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
583
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000584 if (ipmr_fill_mroute(net, skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700585 nlh->nlmsg_len = (skb_tail_pointer(skb) -
586 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 } else {
588 nlh->nlmsg_type = NLMSG_ERROR;
589 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
590 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700591 e = NLMSG_DATA(nlh);
592 e->error = -EMSGSIZE;
593 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 }
Thomas Graf2942e902006-08-15 00:30:25 -0700595
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000596 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 } else
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000598 ip_mr_forward(net, skb, c, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 }
600}
601
602/*
603 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
604 * expects the following bizarre scheme.
605 *
606 * Called under mrt_lock.
607 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900608
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000609static int ipmr_cache_report(struct net *net,
610 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300613 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 struct igmphdr *igmp;
615 struct igmpmsg *msg;
616 int ret;
617
618#ifdef CONFIG_IP_PIMSM
619 if (assert == IGMPMSG_WHOLEPKT)
620 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
621 else
622#endif
623 skb = alloc_skb(128, GFP_ATOMIC);
624
Stephen Hemminger132adf52007-03-08 20:44:43 -0800625 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return -ENOBUFS;
627
628#ifdef CONFIG_IP_PIMSM
629 if (assert == IGMPMSG_WHOLEPKT) {
630 /* Ugly, but we have no choice with this interface.
631 Duplicate old header, fix ihl, length etc.
632 And all this only to mangle msg->im_msgtype and
633 to set msg->im_mbz to "mbz" :-)
634 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300635 skb_push(skb, sizeof(struct iphdr));
636 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300637 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300638 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700639 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 msg->im_msgtype = IGMPMSG_WHOLEPKT;
641 msg->im_mbz = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000642 msg->im_vif = net->ipv4.mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700643 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
644 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
645 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900646 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900648 {
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 /*
651 * Copy the IP header
652 */
653
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700654 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300655 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300656 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700657 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
658 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000660 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662 /*
663 * Add our header
664 */
665
Jianjun Kongc354e122008-11-03 00:28:02 -0800666 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 igmp->type =
668 msg->im_msgtype = assert;
669 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700670 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700671 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000674 if (net->ipv4.mroute_sk == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 kfree_skb(skb);
676 return -EINVAL;
677 }
678
679 /*
680 * Deliver to mrouted
681 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000682 ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
Benjamin Thery70a269e2009-01-22 04:56:15 +0000683 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (net_ratelimit())
685 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
686 kfree_skb(skb);
687 }
688
689 return ret;
690}
691
692/*
693 * Queue a packet for resolution. It gets locked cache entry!
694 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696static int
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000697ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
Patrick McHardy862465f2010-04-13 05:03:21 +0000699 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 int err;
701 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700702 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +0000705 list_for_each_entry(c, &net->ipv4.mfc_unres_queue, list) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000706 if (c->mfc_mcastgrp == iph->daddr &&
Patrick McHardy862465f2010-04-13 05:03:21 +0000707 c->mfc_origin == iph->saddr) {
708 found = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 break;
Patrick McHardy862465f2010-04-13 05:03:21 +0000710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 }
712
Patrick McHardy862465f2010-04-13 05:03:21 +0000713 if (!found) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /*
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 McHardy862465f2010-04-13 05:03:21 +0000749 list_add(&c->list, &net->ipv4.mfc_unres_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Patrick McHardye258beb2010-04-13 05:03:19 +0000751 mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 }
753
754 /*
755 * See if we can append the packet
756 */
757 if (c->mfc_un.unres.unresolved.qlen>3) {
758 kfree_skb(skb);
759 err = -ENOBUFS;
760 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800761 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 err = 0;
763 }
764
765 spin_unlock_bh(&mfc_unres_lock);
766 return err;
767}
768
769/*
770 * MFC cache manipulation by user space mroute daemon
771 */
772
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000773static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 int line;
Patrick McHardy862465f2010-04-13 05:03:21 +0000776 struct mfc_cache *c, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Jianjun Kongc354e122008-11-03 00:28:02 -0800778 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Patrick McHardy862465f2010-04-13 05:03:21 +0000780 list_for_each_entry_safe(c, next, &net->ipv4.mfc_cache_array[line], list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
782 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
783 write_lock_bh(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +0000784 list_del(&c->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 write_unlock_bh(&mrt_lock);
786
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000787 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return 0;
789 }
790 }
791 return -ENOENT;
792}
793
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000794static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Patrick McHardy862465f2010-04-13 05:03:21 +0000796 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 int line;
Patrick McHardy862465f2010-04-13 05:03:21 +0000798 struct mfc_cache *uc, *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Patrick McHardya50436f22010-03-17 06:04:14 +0000800 if (mfc->mfcc_parent >= MAXVIFS)
801 return -ENFILE;
802
Jianjun Kongc354e122008-11-03 00:28:02 -0800803 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Patrick McHardy862465f2010-04-13 05:03:21 +0000805 list_for_each_entry(c, &net->ipv4.mfc_cache_array[line], list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
Patrick McHardy862465f2010-04-13 05:03:21 +0000807 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
808 found = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 break;
Patrick McHardy862465f2010-04-13 05:03:21 +0000810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
812
Patrick McHardy862465f2010-04-13 05:03:21 +0000813 if (found) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 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);
Patrick McHardy862465f2010-04-13 05:03:21 +0000838 list_add(&c->list, &net->ipv4.mfc_cache_array[line]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 write_unlock_bh(&mrt_lock);
840
841 /*
842 * Check to see if we resolved a queued list. If so we
843 * need to send on the frames and tidy up.
844 */
845 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +0000846 list_for_each_entry(uc, &net->ipv4.mfc_unres_queue, list) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000847 if (uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
Patrick McHardy862465f2010-04-13 05:03:21 +0000849 list_del(&uc->list);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000850 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 break;
852 }
853 }
Patrick McHardy862465f2010-04-13 05:03:21 +0000854 if (list_empty(&net->ipv4.mfc_unres_queue))
Patrick McHardye258beb2010-04-13 05:03:19 +0000855 del_timer(&net->ipv4.ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 spin_unlock_bh(&mfc_unres_lock);
857
858 if (uc) {
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000859 ipmr_cache_resolve(net, uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000860 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
862 return 0;
863}
864
865/*
866 * Close the multicast socket, and clear the vif tables etc
867 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900868
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000869static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000872 LIST_HEAD(list);
Patrick McHardy862465f2010-04-13 05:03:21 +0000873 struct mfc_cache *c, *next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /*
876 * Shut down all active vif entries
877 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000878 for (i = 0; i < net->ipv4.maxvif; i++) {
879 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000880 vif_delete(net, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000882 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 /*
885 * Wipe the cache
886 */
Patrick McHardy862465f2010-04-13 05:03:21 +0000887 for (i = 0; i < MFC_LINES; i++) {
888 list_for_each_entry_safe(c, next, &net->ipv4.mfc_cache_array[i], list) {
889 if (c->mfc_flags&MFC_STATIC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 write_lock_bh(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +0000892 list_del(&c->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 write_unlock_bh(&mrt_lock);
894
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000895 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897 }
898
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000899 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +0000901 list_for_each_entry_safe(c, next, &net->ipv4.mfc_unres_queue, list) {
902 list_del(&c->list);
Patrick McHardyd658f8a2010-04-13 05:03:20 +0000903 ipmr_destroy_unres(net, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
905 spin_unlock_bh(&mfc_unres_lock);
906 }
907}
908
909static void mrtsock_destruct(struct sock *sk)
910{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000911 struct net *net = sock_net(sk);
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000914 if (sk == net->ipv4.mroute_sk) {
915 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000918 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 write_unlock_bh(&mrt_lock);
920
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000921 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 }
923 rtnl_unlock();
924}
925
926/*
927 * Socket options and virtual interface manipulation. The whole
928 * virtual interface system is a complete heap, but unfortunately
929 * that's how BSD mrouted happens to think. Maybe one day with a proper
930 * MOSPF/PIM router set up we can clean this up.
931 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900932
David S. Millerb7058842009-09-30 16:12:20 -0700933int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 int ret;
936 struct vifctl vif;
937 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000938 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900939
Stephen Hemminger132adf52007-03-08 20:44:43 -0800940 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000941 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 return -EACCES;
943 }
944
Stephen Hemminger132adf52007-03-08 20:44:43 -0800945 switch (optname) {
946 case MRT_INIT:
947 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000948 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800949 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800950 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800951 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Stephen Hemminger132adf52007-03-08 20:44:43 -0800953 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000954 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800956 return -EADDRINUSE;
957 }
958
959 ret = ip_ra_control(sk, 1, mrtsock_destruct);
960 if (ret == 0) {
961 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000962 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800963 write_unlock_bh(&mrt_lock);
964
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000965 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800966 }
967 rtnl_unlock();
968 return ret;
969 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000970 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800971 return -EACCES;
972 return ip_ra_control(sk, 0, NULL);
973 case MRT_ADD_VIF:
974 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800975 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800976 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800977 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800978 return -EFAULT;
979 if (vif.vifc_vifi >= MAXVIFS)
980 return -ENFILE;
981 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -0800982 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000983 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800984 } else {
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000985 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800986 }
987 rtnl_unlock();
988 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 /*
991 * Manipulate the forwarding caches. These live
992 * in a sort of kernel/user symbiosis.
993 */
Stephen Hemminger132adf52007-03-08 20:44:43 -0800994 case MRT_ADD_MFC:
995 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -0800996 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800997 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800998 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800999 return -EFAULT;
1000 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001001 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001002 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001003 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001004 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001005 rtnl_unlock();
1006 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 /*
1008 * Control PIM assert.
1009 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001010 case MRT_ASSERT:
1011 {
1012 int v;
1013 if (get_user(v,(int __user *)optval))
1014 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001015 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001016 return 0;
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001019 case MRT_PIM:
1020 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001021 int v;
1022
Stephen Hemminger132adf52007-03-08 20:44:43 -08001023 if (get_user(v,(int __user *)optval))
1024 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001025 v = (v) ? 1 : 0;
1026
Stephen Hemminger132adf52007-03-08 20:44:43 -08001027 rtnl_lock();
1028 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001029 if (v != net->ipv4.mroute_do_pim) {
1030 net->ipv4.mroute_do_pim = v;
1031 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001033 rtnl_unlock();
1034 return ret;
1035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001037 /*
1038 * Spurious command, or MRT_VERSION which you cannot
1039 * set.
1040 */
1041 default:
1042 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044}
1045
1046/*
1047 * Getsock opt support for the multicast routing system.
1048 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001049
Jianjun Kongc354e122008-11-03 00:28:02 -08001050int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
1052 int olr;
1053 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001054 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Jianjun Kongc354e122008-11-03 00:28:02 -08001056 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057#ifdef CONFIG_IP_PIMSM
1058 optname!=MRT_PIM &&
1059#endif
1060 optname!=MRT_ASSERT)
1061 return -ENOPROTOOPT;
1062
1063 if (get_user(olr, optlen))
1064 return -EFAULT;
1065
1066 olr = min_t(unsigned int, olr, sizeof(int));
1067 if (olr < 0)
1068 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001069
Jianjun Kongc354e122008-11-03 00:28:02 -08001070 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001072 if (optname == MRT_VERSION)
1073 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001075 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001076 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077#endif
1078 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001079 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001080 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return -EFAULT;
1082 return 0;
1083}
1084
1085/*
1086 * The IP multicast ioctl support routines.
1087 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1090{
1091 struct sioc_sg_req sr;
1092 struct sioc_vif_req vr;
1093 struct vif_device *vif;
1094 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001095 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001096
Stephen Hemminger132adf52007-03-08 20:44:43 -08001097 switch (cmd) {
1098 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001099 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001100 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001101 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001102 return -EINVAL;
1103 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001104 vif = &net->ipv4.vif_table[vr.vifi];
1105 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001106 vr.icount = vif->pkt_in;
1107 vr.ocount = vif->pkt_out;
1108 vr.ibytes = vif->bytes_in;
1109 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001111
Jianjun Kongc354e122008-11-03 00:28:02 -08001112 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001114 return 0;
1115 }
1116 read_unlock(&mrt_lock);
1117 return -EADDRNOTAVAIL;
1118 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001119 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001120 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Stephen Hemminger132adf52007-03-08 20:44:43 -08001122 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001123 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001124 if (c) {
1125 sr.pktcnt = c->mfc_un.res.pkt;
1126 sr.bytecnt = c->mfc_un.res.bytes;
1127 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001129
Jianjun Kongc354e122008-11-03 00:28:02 -08001130 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001131 return -EFAULT;
1132 return 0;
1133 }
1134 read_unlock(&mrt_lock);
1135 return -EADDRNOTAVAIL;
1136 default:
1137 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 }
1139}
1140
1141
1142static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1143{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001144 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001145 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 struct vif_device *v;
1147 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001148 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (event != NETDEV_UNREGISTER)
1151 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001152 v = &net->ipv4.vif_table[0];
1153 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001154 if (v->dev == dev)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001155 vif_delete(net, ct, 1, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001157 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return NOTIFY_DONE;
1159}
1160
1161
Jianjun Kongc354e122008-11-03 00:28:02 -08001162static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 .notifier_call = ipmr_device_event,
1164};
1165
1166/*
1167 * Encapsulate a packet by attaching a valid IPIP header to it.
1168 * This avoids tunnel drivers and other mess and gives us the speed so
1169 * important for multicast video.
1170 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001171
Al Viro114c7842006-09-27 18:39:29 -07001172static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001174 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001175 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001176
1177 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001178 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001179 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001180 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001183 iph->tos = old_iph->tos;
1184 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 iph->frag_off = 0;
1186 iph->daddr = daddr;
1187 iph->saddr = saddr;
1188 iph->protocol = IPPROTO_IPIP;
1189 iph->ihl = 5;
1190 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001191 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 ip_send_check(iph);
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1195 nf_reset(skb);
1196}
1197
1198static inline int ipmr_forward_finish(struct sk_buff *skb)
1199{
1200 struct ip_options * opt = &(IPCB(skb)->opt);
1201
Eric Dumazetadf30902009-06-02 05:19:30 +00001202 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 if (unlikely(opt->optlen))
1205 ip_forward_options(skb);
1206
1207 return dst_output(skb);
1208}
1209
1210/*
1211 * Processing handlers for ipmr_forward
1212 */
1213
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001214static void ipmr_queue_xmit(struct net *net, struct sk_buff *skb,
1215 struct mfc_cache *c, int vifi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001217 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001218 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 struct net_device *dev;
1220 struct rtable *rt;
1221 int encap = 0;
1222
1223 if (vif->dev == NULL)
1224 goto out_free;
1225
1226#ifdef CONFIG_IP_PIMSM
1227 if (vif->flags & VIFF_REGISTER) {
1228 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001229 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001230 vif->dev->stats.tx_bytes += skb->len;
1231 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001232 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001233 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235#endif
1236
1237 if (vif->flags&VIFF_TUNNEL) {
1238 struct flowi fl = { .oif = vif->link,
1239 .nl_u = { .ip4_u =
1240 { .daddr = vif->remote,
1241 .saddr = vif->local,
1242 .tos = RT_TOS(iph->tos) } },
1243 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001244 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 goto out_free;
1246 encap = sizeof(struct iphdr);
1247 } else {
1248 struct flowi fl = { .oif = vif->link,
1249 .nl_u = { .ip4_u =
1250 { .daddr = iph->daddr,
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 }
1256
1257 dev = rt->u.dst.dev;
1258
1259 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1260 /* Do not fragment multicasts. Alas, IPv4 does not
1261 allow to send ICMP, so that packets will disappear
1262 to blackhole.
1263 */
1264
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001265 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 ip_rt_put(rt);
1267 goto out_free;
1268 }
1269
1270 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1271
1272 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001273 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 goto out_free;
1275 }
1276
1277 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001278 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Eric Dumazetadf30902009-06-02 05:19:30 +00001280 skb_dst_drop(skb);
1281 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001282 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 /* FIXME: forward and output firewalls used to be called here.
1285 * What do we do with netfilter? -- RR */
1286 if (vif->flags & VIFF_TUNNEL) {
1287 ip_encap(skb, vif->local, vif->remote);
1288 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001289 vif->dev->stats.tx_packets++;
1290 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 }
1292
1293 IPCB(skb)->flags |= IPSKB_FORWARDED;
1294
1295 /*
1296 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1297 * not only before forwarding, but after forwarding on all output
1298 * interfaces. It is clear, if mrouter runs a multicasting
1299 * program, it should receive packets not depending to what interface
1300 * program is joined.
1301 * If we will not make it, the program will have to join on all
1302 * interfaces. On the other hand, multihoming host (or router, but
1303 * not mrouter) cannot join to more than one interface - it will
1304 * result in receiving multiple packets.
1305 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001306 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 ipmr_forward_finish);
1308 return;
1309
1310out_free:
1311 kfree_skb(skb);
1312 return;
1313}
1314
1315static int ipmr_find_vif(struct net_device *dev)
1316{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001317 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001319 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1320 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 break;
1322 }
1323 return ct;
1324}
1325
1326/* "local" means that we should preserve one skb (for local delivery) */
1327
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001328static int ip_mr_forward(struct net *net, struct sk_buff *skb,
1329 struct mfc_cache *cache, int local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
1331 int psend = -1;
1332 int vif, ct;
1333
1334 vif = cache->mfc_parent;
1335 cache->mfc_un.res.pkt++;
1336 cache->mfc_un.res.bytes += skb->len;
1337
1338 /*
1339 * Wrong interface: drop packet and (maybe) send PIM assert.
1340 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001341 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int true_vifi;
1343
Eric Dumazet511c3f92009-06-02 05:14:27 +00001344 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 /* It is our own packet, looped back.
1346 Very complicated situation...
1347
1348 The best workaround until routing daemons will be
1349 fixed is not to redistribute packet, if it was
1350 send through wrong interface. It means, that
1351 multicast applications WILL NOT work for
1352 (S,G), which have default multicast route pointing
1353 to wrong oif. In any case, it is not a good
1354 idea to use multicasting applications on router.
1355 */
1356 goto dont_forward;
1357 }
1358
1359 cache->mfc_un.res.wrong_if++;
1360 true_vifi = ipmr_find_vif(skb->dev);
1361
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001362 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 /* pimsm uses asserts, when switching from RPT to SPT,
1364 so that we cannot check that packet arrived on an oif.
1365 It is bad, but otherwise we would need to move pretty
1366 large chunk of pimd to kernel. Ough... --ANK
1367 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001368 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001369 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001370 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1372 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001373 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
1375 goto dont_forward;
1376 }
1377
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001378 net->ipv4.vif_table[vif].pkt_in++;
1379 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
1381 /*
1382 * Forward the frame
1383 */
1384 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001385 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (psend != -1) {
1387 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1388 if (skb2)
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001389 ipmr_queue_xmit(net, skb2, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001391 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
1393 }
1394 if (psend != -1) {
1395 if (local) {
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 } else {
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001400 ipmr_queue_xmit(net, skb, cache, psend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 return 0;
1402 }
1403 }
1404
1405dont_forward:
1406 if (!local)
1407 kfree_skb(skb);
1408 return 0;
1409}
1410
1411
1412/*
1413 * Multicast packets for forwarding arrive here
1414 */
1415
1416int ip_mr_input(struct sk_buff *skb)
1417{
1418 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001419 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001420 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 /* Packet is looped back after forward, it should not be
1423 forwarded second time, but still can be delivered locally.
1424 */
1425 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1426 goto dont_forward;
1427
1428 if (!local) {
1429 if (IPCB(skb)->opt.router_alert) {
1430 if (ip_call_ra_chain(skb))
1431 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001432 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 /* IGMPv1 (and broken IGMPv2 implementations sort of
1434 Cisco IOS <= 11.2(8)) do not put router alert
1435 option to IGMP packets destined to routable
1436 groups. It is very bad, because it means
1437 that we can forward NO IGMP messages.
1438 */
1439 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001440 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001441 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001442 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 read_unlock(&mrt_lock);
1444 return 0;
1445 }
1446 read_unlock(&mrt_lock);
1447 }
1448 }
1449
1450 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001451 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 /*
1454 * No usable cache entry
1455 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001456 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 int vif;
1458
1459 if (local) {
1460 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1461 ip_local_deliver(skb);
1462 if (skb2 == NULL) {
1463 read_unlock(&mrt_lock);
1464 return -ENOBUFS;
1465 }
1466 skb = skb2;
1467 }
1468
1469 vif = ipmr_find_vif(skb->dev);
1470 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001471 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 read_unlock(&mrt_lock);
1473
1474 return err;
1475 }
1476 read_unlock(&mrt_lock);
1477 kfree_skb(skb);
1478 return -ENODEV;
1479 }
1480
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001481 ip_mr_forward(net, skb, cache, local);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
1483 read_unlock(&mrt_lock);
1484
1485 if (local)
1486 return ip_local_deliver(skb);
1487
1488 return 0;
1489
1490dont_forward:
1491 if (local)
1492 return ip_local_deliver(skb);
1493 kfree_skb(skb);
1494 return 0;
1495}
1496
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001497#ifdef CONFIG_IP_PIMSM
1498static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001500 struct net_device *reg_dev = NULL;
1501 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001502 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001504 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 /*
1506 Check that:
1507 a. packet is really destinted to a multicast group
1508 b. packet is not a NULL-REGISTER
1509 c. packet is not truncated
1510 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001511 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001513 ntohs(encap->tot_len) + pimlen > skb->len)
1514 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001517 if (net->ipv4.mroute_reg_vif_num >= 0)
1518 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 if (reg_dev)
1520 dev_hold(reg_dev);
1521 read_unlock(&mrt_lock);
1522
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001523 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001524 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001526 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001528 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 skb->protocol = htons(ETH_P_IP);
1531 skb->ip_summed = 0;
1532 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001533 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001534 reg_dev->stats.rx_bytes += skb->len;
1535 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 nf_reset(skb);
1537 netif_rx(skb);
1538 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001541}
1542#endif
1543
1544#ifdef CONFIG_IP_PIMSM_V1
1545/*
1546 * Handle IGMP messages of PIMv1
1547 */
1548
1549int pim_rcv_v1(struct sk_buff * skb)
1550{
1551 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001552 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001553
1554 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1555 goto drop;
1556
1557 pim = igmp_hdr(skb);
1558
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001559 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001560 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1561 goto drop;
1562
1563 if (__pim_rcv(skb, sizeof(*pim))) {
1564drop:
1565 kfree_skb(skb);
1566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return 0;
1568}
1569#endif
1570
1571#ifdef CONFIG_IP_PIMSM_V2
1572static int pim_rcv(struct sk_buff * skb)
1573{
1574 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001576 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 goto drop;
1578
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001579 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001580 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001582 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001583 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 goto drop;
1585
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001586 if (__pim_rcv(skb, sizeof(*pim))) {
1587drop:
1588 kfree_skb(skb);
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return 0;
1591}
1592#endif
1593
1594static int
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001595ipmr_fill_mroute(struct net *net, struct sk_buff *skb, struct mfc_cache *c,
1596 struct rtmsg *rtm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
1598 int ct;
1599 struct rtnexthop *nhp;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001600 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 struct rtattr *mp_head;
1602
Nicolas Dichtel74381892010-03-25 23:45:35 +00001603 /* If cache is unresolved, don't try to parse IIF and OIF */
1604 if (c->mfc_parent > MAXVIFS)
1605 return -ENOENT;
1606
1607 if (VIF_EXISTS(net, c->mfc_parent))
1608 RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Jianjun Kongc354e122008-11-03 00:28:02 -08001610 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
1612 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Nicolas Dichtel74381892010-03-25 23:45:35 +00001613 if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1615 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001616 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 nhp->rtnh_flags = 0;
1618 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001619 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 nhp->rtnh_len = sizeof(*nhp);
1621 }
1622 }
1623 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001624 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 rtm->rtm_type = RTN_MULTICAST;
1626 return 1;
1627
1628rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001629 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 return -EMSGSIZE;
1631}
1632
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001633int ipmr_get_route(struct net *net,
1634 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635{
1636 int err;
1637 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001638 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001641 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Jianjun Kongc354e122008-11-03 00:28:02 -08001643 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001644 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001645 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 struct net_device *dev;
1647 int vif;
1648
1649 if (nowait) {
1650 read_unlock(&mrt_lock);
1651 return -EAGAIN;
1652 }
1653
1654 dev = skb->dev;
1655 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1656 read_unlock(&mrt_lock);
1657 return -ENODEV;
1658 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001659 skb2 = skb_clone(skb, GFP_ATOMIC);
1660 if (!skb2) {
1661 read_unlock(&mrt_lock);
1662 return -ENOMEM;
1663 }
1664
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001665 skb_push(skb2, sizeof(struct iphdr));
1666 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001667 iph = ip_hdr(skb2);
1668 iph->ihl = sizeof(struct iphdr) >> 2;
1669 iph->saddr = rt->rt_src;
1670 iph->daddr = rt->rt_dst;
1671 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001672 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 read_unlock(&mrt_lock);
1674 return err;
1675 }
1676
1677 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1678 cache->mfc_flags |= MFC_NOTIFY;
Patrick McHardyd658f8a2010-04-13 05:03:20 +00001679 err = ipmr_fill_mroute(net, skb, cache, rtm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 read_unlock(&mrt_lock);
1681 return err;
1682}
1683
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001684#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685/*
1686 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1687 */
1688struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001689 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 int ct;
1691};
1692
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001693static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1694 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 loff_t pos)
1696{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001697 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1698 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001700 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001701 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 }
1703 return NULL;
1704}
1705
1706static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001707 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001709 struct net *net = seq_file_net(seq);
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001712 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 : SEQ_START_TOKEN;
1714}
1715
1716static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1717{
1718 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001719 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 ++*pos;
1722 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001723 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001724
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001725 while (++iter->ct < net->ipv4.maxvif) {
1726 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001728 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 }
1730 return NULL;
1731}
1732
1733static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001734 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
1736 read_unlock(&mrt_lock);
1737}
1738
1739static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1740{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001741 struct net *net = seq_file_net(seq);
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001744 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1746 } else {
1747 const struct vif_device *vif = v;
1748 const char *name = vif->dev ? vif->dev->name : "none";
1749
1750 seq_printf(seq,
1751 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001752 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001753 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 vif->bytes_out, vif->pkt_out,
1755 vif->flags, vif->local, vif->remote);
1756 }
1757 return 0;
1758}
1759
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001760static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 .start = ipmr_vif_seq_start,
1762 .next = ipmr_vif_seq_next,
1763 .stop = ipmr_vif_seq_stop,
1764 .show = ipmr_vif_seq_show,
1765};
1766
1767static int ipmr_vif_open(struct inode *inode, struct file *file)
1768{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001769 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1770 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771}
1772
Arjan van de Ven9a321442007-02-12 00:55:35 -08001773static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 .owner = THIS_MODULE,
1775 .open = ipmr_vif_open,
1776 .read = seq_read,
1777 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001778 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779};
1780
1781struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001782 struct seq_net_private p;
Patrick McHardy862465f2010-04-13 05:03:21 +00001783 struct list_head *cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 int ct;
1785};
1786
1787
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001788static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1789 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790{
1791 struct mfc_cache *mfc;
1792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 read_lock(&mrt_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001794 for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
1795 it->cache = &net->ipv4.mfc_cache_array[it->ct];
1796 list_for_each_entry(mfc, it->cache, list)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001797 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 return mfc;
Patrick McHardy862465f2010-04-13 05:03:21 +00001799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 read_unlock(&mrt_lock);
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001803 it->cache = &net->ipv4.mfc_unres_queue;
1804 list_for_each_entry(mfc, it->cache, list)
Patrick McHardye258beb2010-04-13 05:03:19 +00001805 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 return mfc;
1807 spin_unlock_bh(&mfc_unres_lock);
1808
1809 it->cache = NULL;
1810 return NULL;
1811}
1812
1813
1814static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1815{
1816 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001817 struct net *net = seq_file_net(seq);
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 it->cache = NULL;
1820 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001821 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 : SEQ_START_TOKEN;
1823}
1824
1825static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1826{
1827 struct mfc_cache *mfc = v;
1828 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001829 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 ++*pos;
1832
1833 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001834 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835
Patrick McHardy862465f2010-04-13 05:03:21 +00001836 if (mfc->list.next != it->cache)
1837 return list_entry(mfc->list.next, struct mfc_cache, list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001838
Patrick McHardye258beb2010-04-13 05:03:19 +00001839 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 goto end_of_list;
1841
Patrick McHardy862465f2010-04-13 05:03:21 +00001842 BUG_ON(it->cache != &net->ipv4.mfc_cache_array[it->ct]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 while (++it->ct < MFC_LINES) {
Patrick McHardy862465f2010-04-13 05:03:21 +00001845 it->cache = &net->ipv4.mfc_cache_array[it->ct];
1846 if (list_empty(it->cache))
1847 continue;
1848 return list_first_entry(it->cache, struct mfc_cache, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 }
1850
1851 /* exhausted cache_array, show unresolved */
1852 read_unlock(&mrt_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001853 it->cache = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 spin_lock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001857 if (!list_empty(it->cache))
1858 return list_first_entry(it->cache, struct mfc_cache, list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 end_of_list:
1861 spin_unlock_bh(&mfc_unres_lock);
1862 it->cache = NULL;
1863
1864 return NULL;
1865}
1866
1867static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1868{
1869 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001870 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Patrick McHardye258beb2010-04-13 05:03:19 +00001872 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 spin_unlock_bh(&mfc_unres_lock);
Patrick McHardy862465f2010-04-13 05:03:21 +00001874 else if (it->cache == &net->ipv4.mfc_cache_array[it->ct])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 read_unlock(&mrt_lock);
1876}
1877
1878static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1879{
1880 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001881 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882
1883 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001884 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1886 } else {
1887 const struct mfc_cache *mfc = v;
1888 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001889
Benjamin Thery999890b2008-12-03 22:22:16 -08001890 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 (unsigned long) mfc->mfc_mcastgrp,
1892 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001893 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Patrick McHardye258beb2010-04-13 05:03:19 +00001895 if (it->cache != &net->ipv4.mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001896 seq_printf(seq, " %8lu %8lu %8lu",
1897 mfc->mfc_un.res.pkt,
1898 mfc->mfc_un.res.bytes,
1899 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001900 for (n = mfc->mfc_un.res.minvif;
1901 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001902 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001903 mfc->mfc_un.res.ttls[n] < 255)
1904 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001905 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 n, mfc->mfc_un.res.ttls[n]);
1907 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001908 } else {
1909 /* unresolved mfc_caches don't contain
1910 * pkt, bytes and wrong_if values
1911 */
1912 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 }
1914 seq_putc(seq, '\n');
1915 }
1916 return 0;
1917}
1918
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001919static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 .start = ipmr_mfc_seq_start,
1921 .next = ipmr_mfc_seq_next,
1922 .stop = ipmr_mfc_seq_stop,
1923 .show = ipmr_mfc_seq_show,
1924};
1925
1926static int ipmr_mfc_open(struct inode *inode, struct file *file)
1927{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001928 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1929 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930}
1931
Arjan van de Ven9a321442007-02-12 00:55:35 -08001932static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 .owner = THIS_MODULE,
1934 .open = ipmr_mfc_open,
1935 .read = seq_read,
1936 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001937 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001939#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001942static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001944 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945};
1946#endif
1947
1948
1949/*
1950 * Setup for IP multicast routing
1951 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001952static int __net_init ipmr_net_init(struct net *net)
1953{
Patrick McHardy862465f2010-04-13 05:03:21 +00001954 unsigned int i;
Benjamin Therycf958ae32009-01-22 04:56:16 +00001955 int err = 0;
1956
1957 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1958 GFP_KERNEL);
1959 if (!net->ipv4.vif_table) {
1960 err = -ENOMEM;
1961 goto fail;
1962 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001963
1964 /* Forwarding cache */
1965 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
Patrick McHardy862465f2010-04-13 05:03:21 +00001966 sizeof(struct list_head),
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001967 GFP_KERNEL);
1968 if (!net->ipv4.mfc_cache_array) {
1969 err = -ENOMEM;
1970 goto fail_mfc_cache;
1971 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001972
Patrick McHardy862465f2010-04-13 05:03:21 +00001973 for (i = 0; i < MFC_LINES; i++)
1974 INIT_LIST_HEAD(&net->ipv4.mfc_cache_array[i]);
1975
1976 INIT_LIST_HEAD(&net->ipv4.mfc_unres_queue);
1977
Patrick McHardye258beb2010-04-13 05:03:19 +00001978 setup_timer(&net->ipv4.ipmr_expire_timer, ipmr_expire_process,
1979 (unsigned long)net);
1980
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001981#ifdef CONFIG_IP_PIMSM
1982 net->ipv4.mroute_reg_vif_num = -1;
1983#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001984
1985#ifdef CONFIG_PROC_FS
1986 err = -ENOMEM;
1987 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
1988 goto proc_vif_fail;
1989 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
1990 goto proc_cache_fail;
1991#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001992 return 0;
1993
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001994#ifdef CONFIG_PROC_FS
1995proc_cache_fail:
1996 proc_net_remove(net, "ip_mr_vif");
1997proc_vif_fail:
1998 kfree(net->ipv4.mfc_cache_array);
1999#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002000fail_mfc_cache:
2001 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002002fail:
2003 return err;
2004}
2005
2006static void __net_exit ipmr_net_exit(struct net *net)
2007{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002008#ifdef CONFIG_PROC_FS
2009 proc_net_remove(net, "ip_mr_cache");
2010 proc_net_remove(net, "ip_mr_vif");
2011#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002012 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002013 kfree(net->ipv4.vif_table);
2014}
2015
2016static struct pernet_operations ipmr_net_ops = {
2017 .init = ipmr_net_init,
2018 .exit = ipmr_net_exit,
2019};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002020
Wang Chen03d2f892008-07-03 12:13:36 +08002021int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
Wang Chen03d2f892008-07-03 12:13:36 +08002023 int err;
2024
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2026 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002027 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002028 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002029 if (!mrt_cachep)
2030 return -ENOMEM;
2031
Benjamin Therycf958ae32009-01-22 04:56:16 +00002032 err = register_pernet_subsys(&ipmr_net_ops);
2033 if (err)
2034 goto reg_pernet_fail;
2035
Wang Chen03d2f892008-07-03 12:13:36 +08002036 err = register_netdevice_notifier(&ip_mr_notifier);
2037 if (err)
2038 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002039#ifdef CONFIG_IP_PIMSM_V2
2040 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2041 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2042 err = -EAGAIN;
2043 goto add_proto_fail;
2044 }
2045#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002046 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002047
Tom Goff403dbb92009-06-14 03:16:13 -07002048#ifdef CONFIG_IP_PIMSM_V2
2049add_proto_fail:
2050 unregister_netdevice_notifier(&ip_mr_notifier);
2051#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002052reg_notif_fail:
Benjamin Therycf958ae32009-01-22 04:56:16 +00002053 unregister_pernet_subsys(&ipmr_net_ops);
2054reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002055 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002056 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057}